Vue 3.3 是否不再支持 CoffeeScript 等自定义脚本语言?
Vue 3.3+ 与 CoffeeScript 集成崩溃问题分析
问题概述
使用Vite + Vue开发项目,尝试将CoffeeScript作为脚本语言,在Vue 3.2版本中可正常运行,但升级到Vue 3.3及以上版本时,项目编译过程中会因语法错误崩溃。
项目配置与代码示例
Vite配置文件(vite.config.js)
import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import CoffeeScript from "coffeescript" export default defineConfig({ plugins: [ vue(), { name: 'coffee_compile', transform: function(src, id) { // 编译coffee文件为JavaScript if (/\.coffee$/.test(id)) { var {js, sourceMap} = CoffeeScript.compile(src, { sourceMap: true }) return { code: js, map: sourceMap } } } } ], })
App.vue代码
<script lang='coffee'> import { ref } from 'vue' export default data: -> { count: ref(0) } </script> <template> <div> <button type="button" @click="count++">count is {{ count }}</button> </div> </template> <style scoped> </style>
版本差异表现
Vue 3.2版本行为
@vitejs/plugin-vue调用@vue/compiler-sfc生成的代码,会将<script>标签内容以lang.coffee模块的形式单独导入,后续由自定义CoffeeScript编译插件处理,整个流程运行正常:
import _sfc_main from "/Users/boux/repo/vite_coffee_bug/src/App.vue?vue&type=script&lang.coffee" export * from "/Users/boux/repo/vite_coffee_bug/src/App.vue?vue&type=script&lang.coffee" import { toDisplayString as _toDisplayString, createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" function _sfc_render(_ctx, _cache) { return (_openBlock(), _createElementBlock("div", null, [ _createElementVNode("button", { type: "button", onClick: _cache[0] || (_cache[0] = $event => (_ctx.count++)) }, "count is " + _toDisplayString(_ctx.count), 1) ])) } import _export_sfc from 'plugin-vue:export-helper' export default /*#__PURE__*/_export_sfc(_sfc_main, [['render',_sfc_render]])
Vue 3.3版本行为
@vue/compiler-sfc会直接将CoffeeScript代码当作JavaScript进行解析,导致抛出语法错误:
error during build: SyntaxError: [vue/compiler-sfc] Missing semicolon. (5:6) /Users/boux/repo/vite_coffee_bug/src/App.vue 3 | 4 | export default 5 | data: -> { count: ref(0) } | ^ 6 | </script> 7 | at instantiate (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:653:32) at constructor (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:946:12) at Parser.raise (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:3270:19) at Parser.semicolon (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:3637:10) at Parser.parseExportDefaultExpression (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:13759:10) at Parser.parseExport (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:13663:25) at Parser.parseStatementContent (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:12661:27) at Parser.parseStatementLike (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:12549:17) at Parser.parseModuleItem (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:12526:17) at Parser.parseBlockOrModuleBlockBody (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:13121:36) at Parser.parseBlockBody (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:13114:10) at Parser.parseProgram (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:12437:10) at Parser.parseTopLevel (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:12427:25) at Parser.parse (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:14245:10) at Object.parse (/Users/boux/repo/vite_coffee_bug/node_modules/@babel/parser/lib/index.js:14286:38) at parse (/Users/boux/repo/vite_coffee_bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:15811:25) at new ScriptCompileContext (/Users/boux/repo/vite_coffee_bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:15827:43) at Object.compileScript (/Users/boux/repo/vite_coffee_bug/node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js:19766:15) at resolveScript (file:///Users/boux/repo/vite_coffee_bug/node_modules/@vitejs/plugin-vue/dist/index.mjs:285:31) at genScriptCode (file:///Users/boux/repo/vite_coffee_bug/node_modules/@vitejs/plugin-vue/dist/index.mjs:2471:18) at transformMain (file:///Users/boux/repo/vite_coffee_bug/node_modules/@vitejs/plugin-vue/dist/index.mjs:2284:54) at Object.transform (file:///Users/boux/repo/vite_coffee_bug/node_modules/@vitejs/plugin-vue/dist/index.mjs:2796:16) at file:///Users/boux/repo/vite_coffee_bug/node_modules/rollup/dist/es/shared/node-entry.js:24551:40
问题根源分析
这是Vue编译器处理<script>标签代码方式的未文档化变更,大概率属于无意的回归问题。
Vue 3.2版本编译器异常处理逻辑
当解析失败时,编译器会静默返回原脚本内容,因为考虑到用户可能使用自定义语法:
} catch (e) { // silently fallback if parse fails since user may be using custom // babel syntax return script }
Vue 3.3版本编译器异常处理逻辑
当解析失败时,编译器会直接抛出带有代码帧的错误:
} catch (e: any) { e.message = `[vue/compiler-sfc] ${e.message}\n\n${ descriptor.filename }\n${generateCodeFrame( descriptor.source, e.pos + offset, e.pos + offset + 1 )}` throw e }
复现步骤
- 克隆用于复现问题的仓库
- 进入项目目录
- 安装依赖
- 执行构建命令
git clone [复现仓库地址] cd vite-coffee-bug npm install npm run build
后续进展
已在Vue核心仓库提交相关问题,等待官方修复。
内容的提问来源于stack exchange,提问作者Louis Boux
相关产品推荐
相关产品推荐

