webpack/vue-cli工程使用vite专业指北
相信关注前端的小伙伴们,都听说过vite这个最新的前端构建工具了。和它的名字一样,这款由Vue作者尤大大所开发的前端构建最新轮子,与前端传统的构建工具webpack相比,最大的特点就是快,尤其是在开发阶段,由于不需要进行打包,直接使用ES标准中的,且如今大多浏览器已经支持的ESM标准,调试启动速度得到了大幅提升。
对于vite这个工具,网上的相关介绍说明已经很多了,这里就不再多废话了。
不过对于这种前端新出的轮子,相信有些同学,有下面这位同学一样的感受:
对于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.js中pages选项定义的多个配置项 - 添加像这样的入口点:
<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依赖
- 如果之前使用 postcss 8,请添加
-
修复问题 '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
- 在 vite 中, 任何以
-
插件暴露的默认值
- 当
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_URL或publicPath或baseUrl->base -
css配置
css.loaderOptions->css.preprocessorOptionscss.loaderOptions.less.lessOptions.modifyVars->css.preprocessorOptions.less.modifyVars- 在Vue-CLI中,
sass配置可以同时影响sass和scss,而在vite中需要对它们进行单独配置。因此,如果在Vue-CLI中只进行了css.loaderOptions.sass配置,在vite中也会生成css.preprocessorOptions.sass和css.preprocessorOptions.scss两个配置;而如果在Vue-CLI中只进行了css.loaderOptions.scss配置,在vite中则只会生成css.preprocessorOptions.scss配置
-
server配置
- 默认添加
server.strictPort = false配置 process.env.PORT或devServer.port->server.portprocess.env.DEV_HOST或devServer.public或devServer.host->server.host,并将http://或https://替换为''devServer.open,devServer.https->server.open,server.httpsdevServer.proxy->server.proxy, 另外在proxy配置中,进行pathRewrite->rewrite转换
- 默认添加
-
build配置
outputDir->build.outDircss.extract->build.cssCodeSplit- 如果原来有
process.env.MODERN === 'true'配置, 则自动进行build.minify = esbuild配置 - 如果原来有
process.env.GENERATE_SOURCEMAP === 'true'或vueConfig.productionSourceMap或css.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";` } } } - 如果使用 'style-resources-loader' 加载 css 预处理器资源,即
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 规范语法
- 添加 vite 插件
-
对于
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, 参阅这里
- 添加 vite 插件
-
我们修复了错误 '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')
自动转换工具
看到这里的同学,可能已经晕了:这么多配置需要转换,有没有自动化工具来帮我做这些转换适配的工作呢? 有!
目前我们提供了使用Webpack/Vue-CLI的Vue项目自动转换工具,可以直接通过以下命令调用
npm install @originjs/webpack-to-vite -g
webpack-to-vite -d <project path>
代码也已经在github上开源了,地址是github.com/originjs/we… 目前,我们已经使用转换工具,完成了下面这些项目的自动转换:
vue-cli项目
- vue-manage-system -> vue-manage-system-vite
- newbee-mall-vue3-app -> newbee-mall-vue3-app-vite
- vue-realworld-example-app -> vue-realworld-example-app-vite
webpack项目
同时,有很多项目,经过简单的手工修改之后,也可以转换成vite项目了。 当然,转换工具目前还很不完善,还不支持React等其他框架,也有很多webpack、vue-cli的配置转换规则没有实现。我们欢迎开发者同学多提issue、PR,让前端开发者们早日用上vite,完善vite的生态。
Vue Shenzhen MeetUp广告
最后再打一个小广告:深圳的Vue爱好者们注意了,8.21号我们会组织深圳首次Vue开发者MeetUp,作为Vue爱好者的你怎么能错过呢?
赶快登陆vueshenzhen.com/报名吧!