webpack迁移vite小结
Vite 是新一代的前端开发与构建工具,相比于传统的webpack,Vite 有着极速的本地项目启动速度(通常不超过5s)以及极速的热更新速度(几乎无感知)。Vite 官网:https://cn.vitejs.dev/下面分享 Webpack 项目(vue-cli项目)迁移至 Vite 的过程步骤、遇到的问题及解决方式。一、项目背景首先不建议做同时支持webpack和vite,这种只适合自己玩玩,
Vite 是新一代的前端开发与构建工具,相比于传统的webpack,Vite 有着极速的本地项目启动速度(通常不超过5s)以及极速的热更新速度(几乎无感知)。
Vite 官网:https://cn.vitejs.dev/
下面分享 Webpack 项目(vue-cli项目)迁移至 Vite 的过程步骤、遇到的问题及解决方式。
一、项目背景
首先不建议做同时支持webpack和vite,这种只适合自己玩玩,实际项目中要考虑多人开发时的协作和维护成本,只用一种最好。
- 原项目主技术栈及版本:
Vue@3.2.3
typescript@4.3.5
element-plus@1.0.2-beta.70 - 基于vue-cli@4.5.13
- 迁移至vite@2.6.4
二、引入Vite
1、package.json
- scripts里替换命令:
"dev": "vite",
"serve": "vite preview",
"build": "vue-tsc --noEmit && vite build"
- devDependencies移除依赖:
- 添加依赖:
npm i @vitejs/plugin-vue@1.9.3 vite@2.6.4 vue-tsc@0.3.0 -D
2、vite配置文件
移除vue.config.js,
添加vite.config.ts:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src')
}
},
server: {
host: '0.0.0.0',
port: 9000,
proxy: {},
},
})
3、index.html
index.html从public文件夹移动到项目根目录里。
官方说明:https://vitejs.cn/guide/#index-html-and-project-root
4、TS相关
+ tsconfig.json
tsconfig.json的compilerOptions里添加配置:
```json
"isolatedModules": true,
```
+ `/src/shims-vue.d.ts`(没有就新建):
```js
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
```
注意其他第三方的ts声明放入另一个文件`/src/shims-tsx.d.ts`里,和vue-cli模式一致。
5、启动
尝试npm run dev
运行:
(十有八九跑不起来,问题往下翻。)
三、不兼容点
1、环境变量
webpack里的构建时环境变量默认存储在process.env里,
而vite是存储在import.meta.env里,
import.meta.env.MODE: {string} 应用运行的模式。
import.meta.env.BASE_URL: {string} 部署应用时的基本 URL。他由base 配置项决定。
import.meta.env.PROD: {boolean} 应用是否运行在生产环境。
import.meta.env.DEV: {boolean} 应用是否运行在开发环境 (永远与 import.meta.env.PROD相反)。
所以项目里用到的相关地方需要修改,例如process.env.NODE_ENV应替换为import.meta.env.MODE。
2、.env文件
- vue-cli项目的.env文件自定义变量名都是以VUE_APP_开头,
- vite里需要改成以VITE_开头
3、路由history模式
- vue-cli项目如果是部署在服务器子目录下,需要配置vue.config.js里的publicPath字段为子目录路径,例如 /h5
- 而vite里需要配置vite.config.ts里的base字段,且该字段需要以/结尾,例如 /h5/
4、.vue文件的引入方式
vite + ts 里所有.vue文件的引入都必须精确到.vue拓展名,
// 文件路径 src/components/Headers/index.vue
// 原方式
import Headers from '@/components/Headers'
// vite里
import Headers from '@/components/Headers/index.vue'
5、JSX支持
- webpack项目支持jsx是使用的
@vue/babel-plugin-jsx
插件, - vite里对应的插件是
@vitejs/plugin-vue-jsx
vite.config.ts里需要配置:import vueJsx from '@vitejs/plugin-vue-jsx' plugins: [ ..., vueJsx(), ],
6、require.context
require context
是 webpack 提供的特有的模块方法,用于导入一个目录下的所有文件const routes = require.context('./modules', true, /([\w\d-]+)\/routes\.ts/) .keys() .map(id => context(id)) .map(mod => mod.__esModule ? mod.default : mod) .reduce((pre, list) => [...pre, ...list], []) export default new VueRouter({ routes })
- vite里需要使用使用
import.meta.globEager
const routesModules = import.meta.globEager<{default: unknown[]}>('./modules/**/routes.ts') const routes = Object .keys(routesModules) .reduce<any[]>((pre, k) => [...pre, ...routesMod[k].default], []) export default new VueRouter({ routes })
四、第三方插件
一些适用于webpack的第三方插件在vite里肯定不适用了,只能寻找替代方案。
1、svg-sprite-loader
- main.ts里配置全局注册:
import SvgIcon from '@/components/SvgIcon/index.vue' const app = createApp(App) app.component('SvgIcon', SvgIcon)
- vite.config.ts里配置plugins:
plugins: [ ..., svgIcons({ iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')], symbolId: 'icon-[dir]-[name]' }) ],
2、path-to-regexp
- vue-cli项目里可以直接使用path-to-regexp包,估计是vue-cli有相关依赖
- vite里需要手动安装,
npm i path-to-regexp -S
,
最新版是按需引入方式import { pathToRegexp } from 'path-to-regexp'
3、autoprefixer
如果项目配置了autoprefixer,也需要手动安装依赖npm i autoprefixer -D
,
另外vite也能自动读取postcss.config.js配置:
module.exports = {
plugins: [
require('autoprefixer'),
]
}
4、path模块
vite里在运行在浏览器端的业务代码里不支持直接使用path模块书写路径,需要使用path-browserify
// 原方式
import path from 'path'
// vite里(npm i path-browserify -S)
import path from 'path-browserify'
5、全局less引入
- webpack里可以通过配置
style-resources-loader
插件来引入一个less文件作为全局less自动导入,从而在任意.vue文件的<style>
标签里直接使用定义的less变量或less混入等。 - vite里可以配置vite.config.ts:
另外,less定义的变量在定义路径时不能使用alias快捷标识,需要改用绝对路径:css: { preprocessorOptions: { less: { additionalData: `@import "${path.resolve(__dirname, 'src/styles/variable.less')}";`, javascriptEnabled: true, } } },
// 原方式 @imgPath: '~@/assets/images'; // vite里 @imgPath: '/src/assets/images';
五、其他报错问题
1、打包时@charset警告
这个和element-plus使用的@charset配置有关,也可能是其他第三方依赖使用的,总之vite对@charset的使用做了更严格的校验。
解决方法:配置让vite忽略警告。
postcss.config.js
:module.exports = { plugins: [ require('autoprefixer'), // 移除打包element时的@charset警告 { postcssPlugin: 'internal:charset-removal', AtRule: { charset: (atRule) => { if (atRule.name === 'charset') { atRule.remove() } } } }, ] }
2、pre-commit失效问题
项目配置husky + pre-commit 钩子,在git commit时进行代码lint校验,迁移vite后竟然失效了。
原项目用的是typescript@4.3.5 husky@4.3.8,解决步骤:
- 自定义lint命令
- vue-cli项目的lint是直接运行
vue-cli-service lint --fix
就行 - vite里就得自己写了,
"scripts": { "lint": "eslint . --ext .js,.jsx,.vue,.ts,.tsx --fix" }, "husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,jsx,vue,ts,tsx}": [ "npm run lint" ] },
- vue-cli项目的lint是直接运行
- 锁定依赖版本
- 最终发现是依赖版本问题,package.json里的依赖版本在
npm i
后被覆盖了,可能是vite相关依赖覆盖掉了,查找package.lock.json文件可以验证。 - 解决方式就是手动再单独安装一次依赖:
npm i typescript@4.3.5 husky@4.3.8 -D
- 注意package.lock.json不要配置.gitignore忽略,这是版本锁定文件,具体就不再赘述。
- 最终发现是依赖版本问题,package.json里的依赖版本在
- yorkie相关报错
yorkie是配合husky使用的模块,遇到报错时需要手动安装依赖:
bash npm i yorkie -D
六、结语
本来迁移不太复杂的,但由于项目使用了ts和eslint,代码校验比较严格,这使迁移工作至少增加了一倍的工作量,但时间花费是值得的,严谨的代码和规范才能保证项目持续稳定的运行和维护。
附录:
vite.config.ts
完整代码:import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'path' import svgIcons from 'vite-plugin-svg-icons' import vueJsx from '@vitejs/plugin-vue-jsx' // https://vitejs.dev/config/ export default defineConfig({ base: '/yj99admin/', resolve: { alias: { '@': path.resolve(__dirname, './src') } }, server: { host: '0.0.0.0', port: 9000, proxy: {}, plugins: [ vue(), svgIcons({ iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')], symbolId: 'icon-[dir]-[name]' }), vueJsx(), ], css: { preprocessorOptions: { less: { additionalData: `@import "${path.resolve(__dirname, 'src/styles/variable.less')}";`, javascriptEnabled: true, } } }, })
更多推荐
所有评论(0)