English | 简体中文
将 webpack 项目转换为 vite 项目。
webpack-to-vite 已被官方收录,详情
直接通过 npx 使用:
$ npx @originjs/webpack-to-vite <project path>
...或者全局安装使用:
$ npm install @originjs/webpack-to-vite -g
$ webpack-to-vite <project path>
在新目录 filename-toVite
下查看和运行转换完成的 Vite 项目.
注意:默认转换的是 vue-cli 项目。 传入
-t webpack
选项来转换 webpack 项目。
该命令行工具提供以下选项:
$ webpack-to-vite --help
Usage: webpack-to-vite [options] [root]
Options:
-v, --version 显示版本号
-d --rootDir <path> 要转换的项目目录
-t --projectType <type> 项目类型,传入 vue-cli 或 webpack(默认:vue-cli)
-e --entry <type> 整个构建过程的入口,webpack 或 vite 会从那些入口文件开始构建,如果没有指定入口文件,则默认使用 src/main.ts 或 src/main.js
-c --cover 使用此选项,转换的项目文件将覆盖原文件
-h, --help 显示命令帮助
以下是使用工具成功从 webpack 项目转换为 vite 项目的项目列表
- 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-to-vite 自动转换 |
需要手动转换 | |
❌ | 目前不支持 |
-
✅ B01: 在
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
- 必要的依赖:
-
✅ B02: 将 vite 入口文件
index.html
添加到根目录- 支持在
vue.config.js
的pages
选项中配置的多个入口的转换 - 以这种方式添加入口:
<script type="module" src="/src/main.js"></script>
,不需要添加dev-client
入口,因为 vite 默认支持 HMR
- 支持在
-
✅ B03: 将 vite 配置文件
vite.config.js
添加到根目录 -
✅ B04: 在
vite.config.js
中导入和使用需要的插件- 必要的插件:
vite-plugin-env-compatible
- Vue2 项目需要的插件:
vite-plugin-vue2
,默认通过{ jsx: true }
选项启用jsx
支持 - Vue3 项目需要的插件:
@vitejs/plugin-vue
,@vitejs/plugin-vue-jsx
- 必要的插件:
-
✅ B05: 支持省略
.vue
扩展名的导入在自从 vite 发布vite.config.js
中,设置resolve.extensions
配置项为['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
, 然后您可能会遇到 "Problems caused by using alisaes and omitting file suffixes at the same time" 这样的问题, 我们使用补丁来解决这个问题,在 vite 接受相关 PR 之前^2.5.0
版本后已修复
-
✅ B06: sass 支持
- 如果项目使用到
node-sass
依赖,则转换为sass
依赖
- 如果项目使用到
-
✅ B07: postcss 8 支持
- 如果项目使用到
postcss 8
,则添加postcss
依赖
- 如果项目使用到
-
⚠️ B08: 修复问题 '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 项目中所有重复导出的类型或接口,并修改相关导入路径即可
-
⚠️ B09: 删除模块热更新(或 HMR)相关代码,因为 vite 默认支持 HMR- 项目包含 HMR 相关代码时出现以下错误:
index.tsx:6 Uncaught ReferenceError: module is not defined at index.tsx:6
-
⚠️ B10: CSS Modules- 在 vite 中,任何以
.module.css
为后缀名的 CSS 文件都被认为是一个 CSS modules 文件 - 这意味着您需要将以
.css
为后缀的文件转换为以.module.css
为后缀的文件来实现 CSS Modules
- 在 vite 中,任何以
-
✅ B11:
html-webpack-plugin
支持- 插件选项将被应用至
vite-plugin-html
插件 - 注入到
index.html
中的变量将被转换。例如,<%= htmlWebpackPlugin.options.title %>
-><%= title %>
- 从
html-webpack-plugin
中引用injectHtml
和minifyHtml
并且配置选项:
plugins: [ createHtmlPlugin({ inject: { data: { title: value, }, }, minify: { minifyCss: true } }) ]
- 插件选项将被应用至
-
⚠️ B12: 特定的 Vite 插件- 你需要根据项目引入特定的 Vite 插件,该工具并不能做到识别和引入。
- 例如,如果之前使用了
windi.css
,你应该检查 Vite 是否已经支持它,然后参考指导说明,手动引入使用相关的插件(vite-plugin-windicss)。
Vue-CLI 转换是将
vue.config.js
中的配置,转换后设置到vite.config.js
中
-
✅ V01: public path 环境变量
-
process.env.PUBLIC_URL
或publicPath
或baseUrl
->base
-
✅ V02: css 配置
-
css.loaderOptions
->css.preprocessorOptions
-
css.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
配置
-
-
✅ V03: server 配置
- 默认添加
server.strictPort = false
配置 process.env.PORT
或devServer.port
->server.port
process.env.DEV_HOST
或devServer.public
或devServer.host
->server.host
,并将http://
或https://
替换为''
devServer.open
,devServer.https
->server.open
,server.https
devServer.proxy
->server.proxy
,另外在 proxy 配置中,进行pathRewrite
->rewrite
转换
- 默认添加
-
✅ V04: build 配置
outputDir
->build.outDir
css.extract
->build.cssCodeSplit
- 如果配置了
process.env.MODERN === 'true'
,则添加配置build.minify = esbuild
process.env.GENERATE_SOURCEMAP === 'true'
或vueConfig.productionSourceMap
或css.sourceMap
->build.sourcemap
-
✅ V05:
resolve.alias
配置- 默认添加 alias 配置
resolve: { alias: [ { find: '/^~/', replacement: ''}, { find: '@', replacement: path.resolve(__dirname,'src') } ] }
- webpack 中的 alias 配置也会按照类似的方式进行转换
-
✅ V06: 客户端环境变量
- 提取 jsp 脚本 tag 中的环境变量
VUE_APP_VARIABLE
->process.env['VUE_APP_VARIABLE']
-
✅ V07: 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 预处理器资源,即
-
✅ V08: 转换函数形式的 webpack 配置
vue.config.js
模块中的webpackConfigure
和chainWebpack
选项可以定义为对象或者函数- 为了避免在调用这些函数时报错,我们按需初始化
config
选项,并且生成一个临时文件(vue.temp.config.js
)来重新配置html-webpack-plugin
Webpack 转换是将
webpack.config.js
或webpack.base.js/webpack.dev.js/webpack.prod.js
或webpack.build.js/webpack.production.js
中的配置,转换后设置到vite.config.js
中
注意:如果您没有在上述文件中进行 webpack 配置,那么工具将无法进行配置转换,您需要手工配置
-
✅ W01: 构建入口配置
- 如果
entry
类型是string
,entry
->build.rollupOptions.input
- 如果
entry
类型是object
,则将 object 中的每条属性配置到build.rollupOptions.input
中 - 如果
entry
类型是function
,则将 function 的运行结果配置到build.rollupOptions.input
中
- 如果
-
✅ W02: output 配置
output.path
->build.outDir
output.filename
->build.rollupOptions.output.entryFileNames
output.chunkFilename
->build.rollupOptions.output.chunkFileNames
-
✅ W03:
resolve.alias
配置- 添加默认 alias 配置
resolve: { alias: [ { find: '@', replacement: path.resolve(__dirname,'src') } ] }
- webpack 配置的其他别名也会按照上述格式进行转换
- 以
$
结尾的resolve.alias
配置,需要删除$
并配置为确切的值
-
✅ W04: server 配置
devServer.host
,devServer.port
,devServer.proxy
,devServer.https
,devServer.contentBase
->server.host
,server.port
,server.proxy
,server.https
,server.base
-
✅ W05: define 配置
new webpack.DefinePlugin()
->define
-
⚠️ O01: 使用 CommonJS 规范语法,例如require('./')
- 添加 vite 插件
@originjs/vite-plugin-commonjs
,参阅这里 - 请注意该插件只支持部分 CommonJS 规范语法,这意味着一些语法是不支持的,您需要手动转换为 ES Modules 规范语法
- 转换动态 require(例如:
require('@assets/images/' + options.src)
),你可以参考以下步骤
- 使用 Web API
new URL
<template> <img alt="" :src="imgSrc" /> </template> <script> export default { name: 'img', data: () => ({ imgSrc: new URL('./assets/logo.png', import.meta.url).href }) } </script>
...或使用 Vite 的 API
import.meta.glob
- 创建一个模型保存已导入的模块,使用异步方法动态地导入模块并更新到模型中
// src/store/index.js import Vue from 'vue' import Vuex from 'vuex' const assets = import.meta.glob('../assets/**') Vue.use(Vuex) export default new Vuex.Store({ state: { assets: {} }, mutations: { setAssets(state, data) { state.assets = Object.assign({}, state.assets, data) } }, actions: { async getAssets({ commit }, url) { const getAsset = assets[url] if (!getAsset) { commit('setAssets', { [url]: ''}) } else { const asset = await getAsset() commit('setAssets', { [url]: asset.default }) } } } })
- 在
.vue
单文件组件中使用
// img1.vue <template> <img :src="$store.state.assets['../assets/images/' + options.src]" /> </template> <script> export default { name: "img1", props: { options: Object }, watch: { 'options.src': { handler (val) { this.$store.dispatch('getAssets', `../assets/images/${val}`) }, immediate: true, deep: true } } } </script>
- 添加 vite 插件
-
❌ O02: 对于
Element-UI
,参阅这里[vite] Uncaught TypeError: Cannot read property '$isServer' of undefined at node_modules/[email protected]@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/[email protected]@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/[email protected]@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/[email protected]@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)
-
⚠️ O03: 包含多个别名的导入,如:@import '~@/styles/global.scss'
,同时包含了别名~
和@
- 您可以添加别名配置
{ find: /^~@/, replacement: path.resolve(__dirname, 'src') }
到resolve.alias
配置中,并且把该项配置移到别名配置中的第一项
- 您可以添加别名配置
-
⚠️ O04: 在.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'] ] }
参阅这里
- 确保您开启了
-
⚠️ O05: 对于 Webpack 语法require.context
- 添加 vite 插件
@originjs/vite-plugin-require-context
,参阅这里
- 添加 vite 插件
-
✅ O06: 我们修复了错误 'Compiling error when the template of the .vue file has the attribute lang="html"'
- 从
template
标签中移除lang="html"
属性,参阅这里
- 从
-
❌ O07: 不支持 Webpack 语法
require.ensure
-
⚠️ O08: 如下所示,您需要手动把包含别名的动态导入转换为绝对路径或相对路径导入。参阅这里() => import('@/components/views/test.vue')
->
() => import('./components/views/test.vue')
-
⚠️ O09:如果您遇到构建错误[rollup-plugin-dynamic-import-variables] Unexpected token
,则需要删除<img>
标签中的空属性srcset
或srcset=""
-
⚠️ O10: Vite 无法解析一些静态资源,如.PNG
,你可以把它放在assetsInclude
选项中,比如assetsInclude: ['**.PNG']
-
⚠️ O11:支持.md
markdown 文件作为 vue 组件,需要添加vite-plugin-md
插件 -
⚠️ O12: 该错误Uncaught ReferenceError: global is not defined
, 参阅这里-
作为参考,如果您只需要垫片 global,您可以将
<script>window.global = window;</script>
添加到您的index.html
中
-
-
⚠️ O13: 支持将SVG文件作为Vue组件加载- ... 或遇到以下错误时
Uncaught (in promise) DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('/@fs/D:/project/example/node_modules/@example/example.svg') is not a valid name.
- 添加
vite-svg-loader
插件用于 vue 项目 - 添加
vite-plugin-svgr
插件用于 react 项目
-
⚠️ O14: 修复以下错误[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".
- 您需要设置别名,如下所示
resolve: { alias: [ { find: 'vue', replacement: 'vue/dist/vue.esm-bundler.js' } ] }
-
⚠️ O15: 出于以下原因,您可能需要安装vite-plugin-optimize-persist
插件Vite 的依赖预构建是很酷的,大大地提升了开发体验。虽然 Vite 可以智能地检测动态依赖关系,但它的按需检测行为有时会使复杂项目的启动相当缓慢。
[vite] new dependencies found: @material-ui/icons/Dehaze, @material-ui/core/Box, @material-ui/core/Checkbox, updating... [vite] ✨ dependencies updated, reloading page... [vite] new dependencies found: @material-ui/core/Dialog, @material-ui/core/DialogActions, updating... [vite] ✨ dependencies updated, reloading page... [vite] new dependencies found: @material-ui/core/Accordion, @material-ui/core/AccordionSummary, updating... [vite] ✨ dependencies updated, reloading page...