You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
}

复现步骤

  1. 克隆用于复现问题的仓库
  2. 进入项目目录
  3. 安装依赖
  4. 执行构建命令
git clone [复现仓库地址]
cd vite-coffee-bug
npm install
npm run build

后续进展

已在Vue核心仓库提交相关问题,等待官方修复。

内容的提问来源于stack exchange,提问作者Louis Boux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 03:47:36