升级后,Vite/Vue3 抛出内部服务器错误(实验性语法/缺少解析器插件:装饰器)

Sau*_*iel 7 javascript typescript vue.js vuejs3 vite

更新 Vite 后,我无法再启动我的项目,因为我收到以下错误消息:

[vite] Internal server error: This experimental syntax requires enabling one of the following parser plugin(s): "decorators-legacy","decorators"

在更新之前,一切都运行没有问题,而且日志并没有真正帮助我。我在 Vue 中使用 SFC,并为我的组件使用 vue-class-component 和 vue-property-decorator。

我已经更新了:

vite: 2.6.14 -> 2.9.12
@vitejs/plugin-vue: 1.8.0 -> 2.3.3
@vue/compiler-sfc: 3.2.22 -> removed, because it is now a part of plugin-vue
Run Code Online (Sandbox Code Playgroud)

“vite”和“vite build”脚本都会出现此问题。它发现的错误似乎主要发生在组件部分:

// Log

12:55:04 [vite] Internal server error: This experimental syntax requires enabling one of the following parser plugin(s): "decorators-legacy", "decorators". (7:2)
  Plugin: vite:vue
  File: A:/repositories/private/scribe/src/components/app/ui/tooltip/Tooltip.vue
  6  |      <div
  7  |        class="tooltip"
  8  |        :class="{
     |      ^
  9  |          'tooltip--show': show,
  10 |          'tooltip--left': isLeft,
12:55:06 [vite] Internal server error: This experimental syntax requires enabling one of the following parser plugin(s): "decorators-legacy", "decorators". (21:2)
  Plugin: vite:vue
  File: A:/repositories/private/scribe/src/components/app/ui/dropdown/Dropdown.vue
  9  |        :class="{
  10 |          'dropdown-list--expanded': open,
  11 |          'dropdown-list--wide': wide,
     |                                     ^
  12 |          'dropdown-list--expanded-top': open && top,
  13 |        }"
Run Code Online (Sandbox Code Playgroud)

这些是当前安装的依赖项:

// package.json

...

  "dependencies": {
    "@apollo/client": "3.6.9",
    "@fortawesome/fontawesome-svg-core": "6.1.1",
    "@fortawesome/free-brands-svg-icons": "6.1.1",
    "@fortawesome/free-regular-svg-icons": "6.1.1",
    "@fortawesome/free-solid-svg-icons": "6.1.1",
    "@fortawesome/vue-fontawesome": "3.0.0-5",
    "@samuelmeuli/font-manager": "1.4.0",
    "@tiptap/extension-font-family": "2.0.0-beta.24",
    "@tiptap/extension-image": "2.0.0-beta.30",
    "@tiptap/extension-link": "2.0.0-beta.42",
    "@tiptap/extension-text-align": "2.0.0-beta.31",
    "@tiptap/extension-text-style": "2.0.0-beta.26",
    "@tiptap/extension-underline": "2.0.0-beta.25",
    "@tiptap/starter-kit": "2.0.0-beta.189",
    "@tiptap/vue-3": "2.0.0-beta.95",
    "@types/he": "1.1.2",
    "@vue/apollo-composable": "4.0.0-alpha.18",
    "@vuelidate/core": "2.0.0-alpha.41",
    "@vuelidate/validators": "2.0.0-alpha.29",
    "click-outside-vue3": "4.0.1",
    "core-js": "3.23.2",
    "crypto-js": "4.1.1",
    "date-fns": "2.28.0",
    "dompurify": "2.3.8",
    "downloadjs": "1.4.7",
    "graphql": "16.5.0",
    "graphql-tag": "2.12.6",
    "he": "1.2.0",
    "html2canvas": "1.4.1",
    "jsonpack": "1.1.5",
    "localforage": "1.10.0",
    "lodash": "4.17.21",
    "mitt": "3.0.0",
    "object-hash": "3.0.0",
    "prismjs": "1.28.0",
    "register-service-worker": "1.7.2",
    "splitpanes": "3.1.1",
    "typogr": "0.6.8",
    "vite-plugin-markdown": "2.0.2",
    "vue": "3.2.37",
    "vue-class-component": "8.0.0-rc.1",
    "vue-color-kit": "1.0.5",
    "vue-gtag": "2.0.1",
    "vue-i18n": "9.1.10",
    "vue-prism-editor": "2.0.0-alpha.2",
    "vue-property-decorator": "10.0.0-rc.3",
    "vue-router": "4.0.16",
    "vue-scrollto": "2.20.0",
    "vue-waypoint": "4.2.1",
    "vuedraggable": "4.1.0",
    "vuex": "4.0.2"
  },
  "devDependencies": {
    "@intlify/vite-plugin-vue-i18n": "3.4.0",
    "@intlify/vue-i18n-loader": "4.2.0",
    "@types/crypto-js": "4.1.1",
    "@types/dompurify": "2.3.3",
    "@types/downloadjs": "1.4.3",
    "@types/jsonpack": "1.1.1",
    "@types/lodash": "4.14.182",
    "@types/object-hash": "2.2.1",
    "@types/prismjs": "1.26.0",
    "@types/splitpanes": "2.2.1",
    "@typescript-eslint/eslint-plugin": "5.29.0",
    "@typescript-eslint/parser": "5.29.0",
    "@vitejs/plugin-vue": "2.3.3",
    "@vue/eslint-config-prettier": "7.0.0",
    "@vue/eslint-config-typescript": "11.0.0",
    "eslint": "8.18.0",
    "eslint-plugin-import": "2.26.0",
    "eslint-plugin-prettier": "4.0.0",
    "eslint-plugin-vue": "9.1.1",
    "lint-staged": "13.0.2",
    "prettier": "2.7.1",
    "sass": "1.53.0",
    "sass-loader": "13.0.0",
    "typescript": "4.7.4",
    "vite": "2.9.12",
    "vite-plugin-commonjs": "0.5.2",
    "vite-plugin-i18n-resources": "1.0.3",
    "vite-plugin-package-version": "1.0.2",
    "vue-tsc": "0.38.1"
  },
Run Code Online (Sandbox Code Playgroud)

我的打字稿配置:

// tsconfig.json

{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "resolveJsonModule": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "useDefineForClassFields": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ],
    "types": [
      "@intlify/vite-plugin-vue-i18n/client"
    ],
    "typeRoots": [
      "./src/types",
      "./node_modules/@types"
    ],
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.d.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

Run Code Online (Sandbox Code Playgroud)

还有我的Vite配置:

// vite.config.json

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import loadVersion from "vite-plugin-package-version";
import i18nResources from "vite-plugin-i18n-resources";
import markdown, { Mode } from "vite-plugin-markdown";
import { resolve } from "path";

const path = require("path")

function graphQlFile() {
  return {
    name: 'graphql-file',
    transform(src, id) {
      if (id.endsWith(".graphql") || id.endsWith(".gql")) {
        const str = JSON.stringify(src)
        return {
          code: "import gql from 'graphql-tag';const doc="+str+"; export default gql`${doc}`",
          map: null
        }
      }
    }
  }
}

export const ssrTransformCustomDirective = () => {
  return {
    props: [],
    needRuntime: true
  }
}

export default defineConfig({
  server: {
    port: 8080
  },
    resolve: {
    alias: [
      {
        find: "@",
        replacement: path.resolve(__dirname, "src")
      }
    ]
  },
  plugins: [
    vue({
      template: {
        ssr: true,
        compilerOptions: {
          directiveTransforms: {
            "click-outside": ssrTransformCustomDirective,
            "safe-html": ssrTransformCustomDirective
          }
        }
      }
    }),
    i18nResources({
      path: resolve(__dirname, "./src"),
    }),
    loadVersion(),
    graphQlFile(),
    markdown({ mode: Mode.HTML })
  ]
})

Run Code Online (Sandbox Code Playgroud)

Did*_*ids 1

最新更新 - 2022 年 8 月 18 日

该问题现已在 Vue 中修复!

您可以在此处找到修复的拉取请求。


注意:以下信息已过时,请参阅顶部的更新以及下面的进度更新!

找到了此特定错误的解决方案,但请注意,这只是部分解决方案,至少目前如此。在撰写本文时,您需要使用 Vite 的预发布版本来解决该问题。

就我而言,我只需更新以下依赖项:

"@vitejs/plugin-vue": "3.0.0-beta.1",
"vite": "^3.0.0-beta.7",
Run Code Online (Sandbox Code Playgroud)

您在尝试安装这些软件包时可能会遇到问题,因为其他软件包有版本要求,不允许安装 Vite 的 3.x 软件包,在这种情况下,您只需运行以下命令即可:

rm -fr node_modules package-lock.json
npm install --force
Run Code Online (Sandbox Code Playgroud)

之后,您应该能够使用 Vite 进行构建和运行,而不需要它(或 Babel)抱怨装饰器。

坏消息是,在此之后您可能会遇到其他新错误,我认为需要在 Vite 和所有使用它的插件/您特定项目所需的插件中修复这些错误。


更新 - 2022 年 7 月 21 日

该问题似乎来自 Vue 的单文件组件 (SFC) 编译器,现在其 GitHub 存储库中存在一个未解决的问题: https ://github.com/vuejs/core/issues/6318

此外,同一个人似乎已经制定了一个修复该问题的拉取请求,该请求仍然在这里开放: https: //github.com/vuejs/core/pull/6320

从上面的问题和拉取请求来看,我们看到的问题似乎是由使用 before 装饰器明确引起的export default ...,它没有被正确地重写/转换,从而导致了这个问题。

现在,我们要么需要等待,在本地进行更改,要么派生我们自己的副本并应用拉取请求的修复,然后使用我们派生的 SFC 编译器版本。手指交叉,这应该可以解决问题!

编辑:我尝试了修复并可以确认它有效!以下是我目前如何将其应用到我的项目中,以防您(或其他任何人)想尝试。

更改为package.json

"@vitejs/plugin-vue": "3.0.0-beta.1",
"vite": "^3.0.0-beta.7",
Run Code Online (Sandbox Code Playgroud)

创建一个名为的新补丁文件vue-compiler-sfc.patch,其内容如下:

--- node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js.orig    2022-08-02 12:54:51
+++ node_modules/@vue/compiler-sfc/dist/compiler-sfc.cjs.js 2022-08-02 16:10:06
@@ -3352,7 +3352,12 @@
     }).program.body;
     ast.forEach(node => {
         if (node.type === 'ExportDefaultDeclaration') {
-            s.overwrite(node.start, node.declaration.start, `const ${as} = `);
+            if (node.declaration.type === 'ClassDeclaration') {
+                s.overwrite(node.start, node.declaration.id.start, `class `)
+                s.append(`\nconst ${as} = ${node.declaration.id.name}`)
+            } else {
+                s.overwrite(node.start, node.declaration.start, `const ${as} = `)
+            }
         }
         if (node.type === 'ExportNamedDeclaration') {
             for (const specifier of node.specifiers) {

Run Code Online (Sandbox Code Playgroud)

现在只需运行即可npm i应用补丁,您的项目现在应该可以消除此错误,即使只是临时解决方案。