Webpack to Vite
August 5, 2022 · View on GitHub
English | 简体中文
Webpack to Vite
将 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 项目的项目列表
demos
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
转换项
以下是需要转换的配置项列表
图例注解:
| 图例 | 描述 |
|---|---|
| ✅ | 通过 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-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.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转换
- 默认添加
-
✅ V04: 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
-
✅ 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 转换是将
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.outDiroutput.filename->build.rollupOptions.output.entryFileNamesoutput.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/_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) -
⚠️ 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:支持
.mdmarkdown 文件作为 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...