Vite 是新一代的前端开发与构建工具,相比于传统的webpack,Vite 有着极速的本地项目启动速度(通常不超过5s)以及极速的热更新速度(几乎无感知)。
Vite 官网:https://cn.vitejs.dev/
下面分享 Webpack 项目(vue-cli项目)迁移至 Vite 的过程步骤、遇到的问题及解决方式。
首先不建议做同时支持webpack和vite,这种只适合自己玩玩,实际项目中要考虑多人开发时的协作和维护成本,只用一种最好。
"dev": "vite",
"serve": "vite preview",
"build": "vue-tsc --noEmit && vite build"
npm i @vitejs/[email protected] [email protected] [email protected] -D
移除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: {},
},
})
index.html从public文件夹移动到项目根目录里。
官方说明:https://vitejs.cn/guide/#index-html-and-project-root
+ tsconfig.json
tsconfig.json的compilerOptions里添加配置:
```json
"isolatedModules": true,
```
+ `/src/shims-vue.d.ts`(没有就新建):
```js
///
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}
```
注意其他第三方的ts声明放入另一个文件`/src/shims-tsx.d.ts`里,和vue-cli模式一致。
尝试npm run dev
运行:
(十有八九跑不起来,问题往下翻。)
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。
vite + ts 里所有.vue文件的引入都必须精确到.vue拓展名,
// 文件路径 src/components/Headers/index.vue
// 原方式
import Headers from '@/components/Headers'
// vite里
import Headers from '@/components/Headers/index.vue'
@vue/babel-plugin-jsx
插件,@vitejs/plugin-vue-jsx
import vueJsx from '@vitejs/plugin-vue-jsx'
plugins: [
...,
vueJsx(),
],
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 })
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里肯定不适用了,只能寻找替代方案。
改用vite-plugin-svg-icons
import SvgIcon from '@/components/SvgIcon/index.vue'
const app = createApp(App)
app.component('SvgIcon', SvgIcon)
plugins: [
...,
svgIcons({
iconDirs: [path.resolve(process.cwd(), 'src/assets/svgs')],
symbolId: 'icon-[dir]-[name]'
})
],
npm i path-to-regexp -S
,import { pathToRegexp } from 'path-to-regexp'
如果项目配置了autoprefixer,也需要手动安装依赖npm i autoprefixer -D
,
另外vite也能自动读取postcss.config.js配置:
module.exports = {
plugins: [
require('autoprefixer'),
]
}
vite里在运行在浏览器端的业务代码里不支持直接使用path模块书写路径,需要使用path-browserify
// 原方式
import path from 'path'
// vite里(npm i path-browserify -S)
import path from 'path-browserify'
style-resources-loader
插件来引入一个less文件作为全局less自动导入,从而在任意.vue文件的
标签里直接使用定义的less变量或less混入等。css: {
preprocessorOptions: {
less: {
additionalData: `@import "${path.resolve(__dirname, 'src/styles/variable.less')}";`,
javascriptEnabled: true,
}
}
},
另外,less定义的变量在定义路径时不能使用alias快捷标识,需要改用绝对路径:// 原方式
@imgPath: '~@/assets/images';
// vite里
@imgPath: '/src/assets/images';
这个和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()
}
}
}
},
]
}
项目配置husky + pre-commit 钩子,在git commit时进行代码lint校验,迁移vite后竟然失效了。
原项目用的是typescript@4.3.5 husky@4.3.8,解决步骤:
vue-cli-service lint --fix
就行"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"
]
},
npm i
后被覆盖了,可能是vite相关依赖覆盖掉了,查找package.lock.json文件可以验证。npm i typescript@4.3.5 husky@4.3.8 -D
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,
}
}
},
})