webpack&vue-cli迁移vite专业指北

3,689 阅读7分钟

webpack/vue-cli工程使用vite专业指北

相信关注前端的小伙伴们,都听说过vite这个最新的前端构建工具了。和它的名字一样,这款由Vue作者尤大大所开发的前端构建最新轮子,与前端传统的构建工具webpack相比,最大的特点就是,尤其是在开发阶段,由于不需要进行打包,直接使用ES标准中的,且如今大多浏览器已经支持的ESM标准,调试启动速度得到了大幅提升。

对于vite这个工具,网上的相关介绍说明已经很多了,这里就不再多废话了。

不过对于这种前端新出的轮子,相信有些同学,有下面这位同学一样的感受:

tu2.PNG 对于vite这么好的工具,可能很多同学都遇到了和我一样的问题:

这个工具很好,但是我之前的项目打包使用的是webpack/vue-cli,很多webpack/vue-cli的配置在vite中对应的配置是什么呢?使用vite,需要额外进行什么配置呢?有没有什么webpack插件,vite不支持呢?……

那么,有没有这样一份清单,指导webpack/vue-cli项目,如何转换成vite构建呢?

正好,我这里准备了这样一份(不太完全的)使用webpack/vue-cli的Vue工程,迁移到Vite的规则清单,方便大家参考:

Webpack/Vue-cli的Vue工程,迁移到Vite部分规则清单

基础转换规则

  • package.json 中添加必要的 devDependencies 和 dependencies

    • 必要的: vite-plugin-env-compatible, vite-plugin-html, vite,
    • Vue2 必要的: vite-plugin-vue2
    • Vue3 必要的: @vue/compiler-sfc, @vitejs/plugin-vue, @vitejs/plugin-vue-jsx
  • 将 vite 入口文件 index.html 添加到根目录

    • 支持 vue.config.jspages 选项定义的多个配置项
    • 添加像这样的入口点:<script type="module" src="/src/main.js"></script>,不需要添加 dev-client 入口点,因为 vite 默认支持 HMR
  • 将 vite 配置文件 vite.config.js 添加到根目录

  • vite.config.js 中导入和使用必要的插件

    • 必要的 vite-plugin-env-compatible
    • Vue2 必要的: vite-plugin-vue2,通过 { jsx: true } 选项启用 jsx 默认支持
    • Vue3 必要的: @vitejs/plugin-vue, @vitejs/plugin-vue-jsx
  • 支持省略 .vue 扩展名的导入

    • vite.config.js 中,设置 resolve.extensions 配置项为 ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
  • sass 支持

    • 如果之前使用 node-sass 依赖,则转换为 sass 依赖
  • postcss 8 支持

    • 如果之前使用 postcss 8,请添加 postcss 依赖
  • 修复问题 'No matching export for import typescript interface'

    • 请勿在 vite 中重复导出 typescript 类型或接口。 您只能在文件 A 中将其导出,然后在文件 B 中将其导入。不要尝试在文件 B 中将其再次导出。 以下是重复导出类型或接口时出现的错误:
    Uncaught SyntaxError: The requested module '/src/app/reducers/state.ts' does not provide an export named 'RootState'
    
    • 只要删除 typescript 项目中所有重复导出的类型或接口,并修改相关导入路径
  • 删除模块热更新(或 HMR)相关代码,因为 vite 默认支持 HMR

    • 项目包含 HMR 相关代码时出现以下错误:
    index.tsx:6 Uncaught ReferenceError: module is not defined
      at index.tsx:6
    
  • CSS Modules

    • 在 vite 中, 任何以 .module.css 为后缀名的 CSS 文件都被认为是一个 CSS modules 文件
    • 这意味着您需要将以 .css 为后缀文件转换为以 .module.css 为后缀的文件来实现 CSS Modules
  • 插件暴露的默认值

    • index.html 包含 htmlWebpackPlugin.options.variableName 时出现 htmlWebpackPlugin is not defined 错误,需要在 vite.config.js 中添加插件选项:
    plugins: [
      injectHtml:({
        injectData: {
          htmlWebpackPlugin: {
            options: {
              variableName: value
            }
          }
        }
      })
    ]
    

Vue-CLI转换规则

  • public path环境变量

  • process.env.PUBLIC_URLpublicPathbaseUrl -> base

  • css配置

    • css.loaderOptions -> css.preprocessorOptions
    • css.loaderOptions.less.lessOptions.modifyVars -> css.preprocessorOptions.less.modifyVars
    • 在Vue-CLI中,sass配置可以同时影响sassscss,而在vite中需要对它们进行单独配置。因此,如果在Vue-CLI中只进行了css.loaderOptions.sass配置,在vite中也会生成css.preprocessorOptions.sasscss.preprocessorOptions.scss两个配置;而如果在Vue-CLI中只进行了css.loaderOptions.scss配置,在vite中则只会生成css.preprocessorOptions.scss配置
  • server配置

    • 默认添加server.strictPort = false配置
    • process.env.PORTdevServer.port -> server.port
    • process.env.DEV_HOSTdevServer.publicdevServer.host -> server.host,并将http://https:// 替换为 ''
    • devServer.open, devServer.https -> server.open, server.https
    • devServer.proxy -> server.proxy, 另外在proxy配置中,进行pathRewrite -> rewrite转换
  • build配置

    • outputDir -> build.outDir
    • css.extract -> build.cssCodeSplit
    • 如果原来有process.env.MODERN === 'true'配置, 则自动进行 build.minify = esbuild配置
    • 如果原来有 process.env.GENERATE_SOURCEMAP === 'true'vueConfig.productionSourceMapcss.sourceMap配置 ->则进行 build.sourcemap配置
  • resolve.alias配置

    • 默认添加alias配置
    resolve: {
      alias: [
        { find: '/^~/', replacement: ''},
        { find: '@', replacement: path.resolve(__dirname,'src') }
      ]
    }
    
  • webpack中的alias配置也会按照类似的方式进行转换

  • 客户端环境变量

    • 提取jsp脚本tag中的环境变量
    • VUE_APP_VARIABLE -> process.env['VUE_APP_VARIABLE']
  • css 自动化导入

    • 如果使用 'style-resources-loader' 加载 css 预处理器资源,即 pluginOptions['style-resources-loader']。 配置将被转换并写入css.preprocessorOptions
    pluginOptions: {
      'style-resources-loader': {
        preProcessor: 'less',
        patterns: [
          resolve('src/styles/var.less'),
          resolve('src/styles/mixin.less')
        ]
      }
    }
    

    ->

    css: {
      preprocessorOptions: {
        less: {
          additionalData: `@import "src/styles/var.less";@import "src/styles/mixin.less";`
        }
      }
    }
    

Webpack 转换项

  • 构建入口配置

    • 如果 entry 类型是 string , entry -> build.rollupOptions.input
    • 如果 entry 类型是 object , 则将object中的每条属性配置到 build.rollupOptions.input
    • 如果 entry 类型是 function , 则将function的运行结果配置到build.rollupOptions.input
  • outDir配置

    • output.path -> build.outDir
  • resolve.alias 配置

    • 添加默认alias配置
    resolve: {
      alias: [
        { find: '@', replacement: path.resolve(__dirname,'src') }
      ]
    }
    
    • webpack的其他别名配置也会按照上述格式进行转换
    • $结尾的resolve.alias 配置, 需要删除$并配置为准确的值
  • server配置

    • devServer.host, devServer.port, devServer.proxy, devServer.https, devServer.contentBase -> server.host, server.port, server.proxy, server.https, server.base
  • define配置

    • new webpack.DefinePlugin() -> define

其他转换项

  • 使用 CommonJS 规范语法, 例如 require('./')

    • 添加 vite 插件 @originjs/vite-plugin-commonjs, 参阅这里
    • 请注意该插件只支持部分 CommonJS 规范语法, 这意味着一些语法是不支持的, 您需要手动转换为 ES Modules 规范语法
  • 对于 Element-UI, 参阅这里

     [vite] Uncaught TypeError: Cannot read property '$isServer' of undefined
      at node_modules/_element-ui@2.15.1@element-ui/lib/utils/dom.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1189)
      at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12)
      at node_modules/_element-ui@2.15.1@element-ui/lib/utils/popup/popup-manager.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1478)
      at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12)
      at node_modules/_element-ui@2.15.1@element-ui/lib/utils/popup/index.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1701)
      at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12)
      at node_modules/_element-ui@2.15.1@element-ui/lib/utils/vue-popper.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:2546)
      at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12)
      at Object.5 (:8080/node_modules/.vite/element-ui.js?v=675d2c77:6861)
      at __webpack_require__ (:8080/node_modules/.vite/element-ui.js?v=675d2c77:6547)
    
  • 包含多个别名的导入,如: @import '~@/styles/global.scss', 同时包含了别名 ~@

    • 您可以添加别名配置 { find: /^~@/, replacement: path.resolve(__dirname, 'src') }resolve.alias 配置中, 并且把该项配置移到别名配置中的第一项
  • .vue 文件中使用 jsx 语法

    • 确保您开启了 jsx 支持, 在 Vue2 中,需要添加 vite-plugin-vue2 插件并传入 { jsx: true } 配置, 在 Vue3 中需要添加 @vitejs/plugin-vue-jsx 插件
    • 添加 lang="jsx" 属性到 script 标签, 例如 <script lang="jsx"></script>
    • 如果您遇到以下错误
    3:54:29 PM [vite] Internal server error: /Users/Chieffo/Documents/project/Vue-mmPlayer/src/base/mm-icon/mm-icon.vue?vue&type=script&lang.tsx: Duplicate declaration "h" (This is an error on an internal node. Probably an internal error.)
    Plugin: vite-plugin-vue2
    File: /Users/Chieffo/Documents/project/Vue-mmPlayer/src/base/mm-icon/mm-icon.vue?vue&type=script&lang.tsx
        at File.buildCodeFrameError (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/core/lib/transformation/file/file.js:244:12)
        at Scope.checkBlockScopedCollisions (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:421:22)
        at Scope.registerBinding (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:581:16)
        at Scope.registerDeclaration (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:523:14)
        at Object.BlockScoped (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:240:12)
        at Object.newFn (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/visitors.js:212:17)
        at NodePath._call (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:53:20)
        at NodePath.call (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:36:14)
        at NodePath.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:90:31)
        at TraversalContext.visitQueue (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:99:16)
        at TraversalContext.visitMultiple (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:68:17)
        at TraversalContext.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:125:19)
        at Function.traverse.node (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/index.js:76:17)
        at NodePath.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:97:18)
        at TraversalContext.visitQueue (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:99:16)
        at TraversalContext.visitSingle (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:73:19)
    

    您可以尝试更新 babel.config.js 配置文件,如下:

    module.exports = {
      presets: [
        '@vue/app'
      ]
    }
    

    ->

    module.exports = {
      presets: [
        ['@vue/babel-preset-jsx']
      ]
    }
    

    参阅这里

  • 对于 Webpack 语法 require.context

    • 添加 vite 插件 @originjs/vite-plugin-require-context, 参阅这里
  • 我们修复了错误 'Compiling error when the template of the .vue file has the attribute lang="html"'

    • template 标签中移除 lang="html" 属性, 参阅这里
  • 不支持 Webpack 语法 require.ensure

  • 如下所示,您需要手动把包含别名的动态导入转换为绝对路径或相对路径导入。参阅这里

    () => import('@/components/views/test.vue')
    

    ->

    () => import('./components/views/test.vue')
    

自动转换工具

看到这里的同学,可能已经晕了:这么多配置需要转换,有没有自动化工具来帮我做这些转换适配的工作呢? 有!

tu1.jpg

目前我们提供了使用Webpack/Vue-CLI的Vue项目自动转换工具,可以直接通过以下命令调用

npm install @originjs/webpack-to-vite -g
webpack-to-vite -d <project path>

代码也已经在github上开源了,地址是github.com/originjs/we… 目前,我们已经使用转换工具,完成了下面这些项目的自动转换:

vue-cli项目

webpack项目

同时,有很多项目,经过简单的手工修改之后,也可以转换成vite项目了。 当然,转换工具目前还很不完善,还不支持React等其他框架,也有很多webpack、vue-cli的配置转换规则没有实现。我们欢迎开发者同学多提issue、PR,让前端开发者们早日用上vite,完善vite的生态。

Vue Shenzhen MeetUp广告

最后再打一个小广告:深圳的Vue爱好者们注意了,8.21号我们会组织深圳首次Vue开发者MeetUp,作为Vue爱好者的你怎么能错过呢? 赶快登陆vueshenzhen.com/报名吧! tu3.jpg