全網最硬核的Ant-Design-Vue從Vue-cli遷移至Vite
一、前言
眾所周知,Vite作為下一代前端開發與構建工具,就是一個字:快。並且Vite已經作為Vue3預設的構建工具。通過實驗表明,專案遷移後,從Vue-cli的近2分鐘,到Vite的5秒(專案大小不同,時間也不同),提升了幾十倍甚至上百倍的速度。
本文針對老專案從Vue-cli遷移到Vite,提供了全網最全的方案。下面以ant-design-vue-pro為例進行遷移,ant-design-vue版本為1.7.8。
同時,提供了遷移後的倉庫,歡迎Star~
GitHub - Seals-Studio/ant-design-vue-pro-vite
遷移前後對比(參考)
| 構建工具 | 伺服器啟動耗時 | 頁面首次載入速度 (無快取) | 第二次載入速度 (有快取) | 熱更新 HMR | 打包 | | ------- | ----------------- | -------------- | ------------- | ------- | --------- | | Webpack | 83s | 4.78s | 3.35s | 4.78s | 3mins 37s | | Vite | 4.72s (第二次 0.72s) | 1.71s | 1.33s | 瞬間 | 51.45s |
二、刪除package.json相關依賴
- 刪除@vue和babel相關
json
{
"@vue/babel-helper-vue-jsx-merge-props": "^1.2.1",
"@vue/cli-plugin-babel": "^4.5.17",
"@vue/cli-plugin-eslint": "^4.5.17",
"@vue/cli-plugin-router": "^4.5.17",
"@vue/cli-plugin-unit-jest": "^4.5.17",
"@vue/cli-plugin-vuex": "^4.5.17",
"@vue/cli-service": "^4.5.17",
"@vue/eslint-config-standard": "^4.0.0",
"@vue/test-utils": "^1.3.0",
"babel-eslint": "^10.1.0",
"babel-plugin-import": "^1.13.3",
"babel-plugin-transform-remove-console": "^6.9.4",
}
- 刪除loader(webpack外掛)和webpack
json
{
"file-loader": "^6.2.0",
"less-loader": "^5.0.0",
"vue-svg-icon-loader": "^2.1.1",
"git-revision-webpack-plugin": "^3.0.6",
"webpack-theme-color-replacer": "^1.3.26",
}
-
刪除babel.conf.js和jsconfig.json
-
安裝pnpm工具
pnpm是快速的,節省磁碟空間的包管理工具
```bash npm i -g pnpm
淘寶源
pnpm config set registry http://registry.npm.taobao.org
pnpm config set disturl http://npm.taobao.org/dist
pnpm config set NVM_NODEJS_ORG_MIRROR http://npm.taobao.org/mirrors/node
pnpm config set NVM_IOJS_ORG_MIRROR http://npm.taobao.org/mirrors/iojs
pnpm config set PHANTOMJS_CDNURL http://npm.taobao.org/dist/phantomjs
pnpm config set ELECTRON_MIRROR http://npm.taobao.org/mirrors/electron/
pnpm config set SASS_BINARY_SITE http://npm.taobao.org/mirrors/node-sass
pnpm config set SQLITE3_BINARY_SITE http://npm.taobao.org/mirrors/sqlite3
pnpm config set PYTHON_MIRROR http://npm.taobao.org/mirrors/python
```
三、安裝最新版vite和vite-plugin-vue2
bash
pnpm add vite vite-plugin-vue2 -D
四、在根目錄下新建vite.conf.js
```javascript import { defineConfig } from 'vite' // vue2的vite外掛 import { createVuePlugin } from 'vite-plugin-vue2'
export default ({ mode }) => { return defineConfig({ plugins: [ createVuePlugin({ jsx: true }) ] }) }) ```
五、index.html修改
-
移動public/index.html到程式碼根目錄(和package.json同級)
-
在body標籤中新增如下:
```html
```
- 替換htmlWebpackPlugin外掛注入的變數
htmlWebpackPlugin是webpack外掛,所以不能再使用了,vite提供了vite-plugin-html外掛來向index.html注入變數
-
安裝vite-plugin-html
bash pnpm add vite-plugin-html -D
-
修改vite.config.js,新增配置
javascript
plugins: [
// ...
createHtmlPlugin({
minify: true,
inject: {
data: {
title: 'Ant Design Pro',
cdn: {
css: [],
js: [
'//cdn.jsdelivr.net/npm/[email protected]/dist/vue.min.js',
'//cdn.jsdelivr.net/npm/[email protected]/dist/vue-router.min.js',
'//cdn.jsdelivr.net/npm/[email protected]/dist/vuex.min.js',
'//cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js'
]
}
}
}
}),
// ...
]
-
修改index.html
- 修改title
html <title><%= title %></title>
- 修改css和js引入
```html <% for (var i in cdn.css) { %> <link rel="stylesheet" href="<%= cdn.css[i] %>" /> <% } %>
<!-- require cdn assets js --> <% for (var i in cdn.js) { %> <script type="text/javascript" src="<%= cdn.js[i] %>"></script> <% } %>
```
六、環境變數更換
出於安全考慮,vite只能識別以
VITE_
開頭的環境變量了,原VUE_環境變數不生效了,同時,也不能使用process.env.xxx
來讀取環境變量了。需要修改vite.conf.js配置,手動新增process.env.xxx
環境變數
- 修改vite.conf.js配置,新增環境變數
```js import { defineConfig, loadEnv } from 'vite'
export default ({ mode }) => {
const env = loadEnv(mode, process.cwd())
return defineConfig({
define: {
'process.env': { ...env }
},
})
})
```
-
將所有開頭的
VUE_
環境變數全部替換為VITE_
-
將所有的
process.env.NODE_ENV
更改為import.meta.env.MODE
-
將所有開頭為
process.env.
全部更改為import.meta.env.
七、Ant-Design-Vue按需引入
```bash
注意本外掛必須採用1.4.1版本,不能採用最新版2.0.0
pnpm add [email protected]^1.4.1 -D ```
- 增加vite.conf.js配置
javascript
plugins: [
// ...
styleImport({
libs: [
{
libraryName: 'ant-design-vue',
esModule: true,
resolveStyle: (name) => {
return `ant-design-vue/es/${name}/style/index`
},
}
],
}),
// ...
]
八、Ant-Design-Vue引入moment問題
原因是antdv底層引入採用:
import * as moment from "moment";
未相容ESM寫法,參考 github issue: chore: v1 support vite
本文參考[]外掛,寫了一個vite外掛,去修改antdv底層引入moment方式,改為:import moment from moment
- 安裝依賴包
bash
pnpm add [email protected]">=1.20.0 <2.0.0 || >=2.0.0 <3.0.0" -D
pnpm add @rollup/plugin-replace -D
- 修改vite.conf.js配置
```javascript import path from 'path-browserify' import fs from 'fs' import replace from '@rollup/plugin-replace'
// 參考vite-plugin-antdv1-momentjs-resolver外掛,修改正則表示式,相容Windows路徑 // http://github.com/carl-jin/vite-plugin-antdv1-momentjs-resolver/blob/main/src/index.js // 將moment_util.js中import * as moment from moment修改import moment from moment // 原正則表示式 // const antdvDefaultReg = /ant-design-vue\/[\w-\\/].js$/ // 修改後正則表示式 // const antdvDefaultReg = /ant-design-vue[\/|\][\w-\\/].js$/ const AntdMomentResolver = (reg = /ant-design-vue[\/|\][\w-\\/]*.js$/) => { return { name: 'vite-plugin-antdv1-momentjs-resolver', configResolved(config) { // 以來預構建時候替換 esbuild config.optimizeDeps.esbuildOptions.plugins = config.optimizeDeps.esbuildOptions.plugins ? config.optimizeDeps.esbuildOptions.plugins : [] config.optimizeDeps.esbuildOptions.plugins.push({ name: 'replace-code', setup(build) { build.onLoad( { filter: reg, }, (args) => { // 首先獲取原始碼內容 let source = fs.readFileSync(args.path, 'utf8') if (source.indexOf('import * as moment from')) { source = source.replace(/import\s*\sas\smoment\sfrom/g, 'import moment from') } return { contents: source, } } ) }, })
// 新增打包時的替換 rollup
config.plugins.push(
replace({
values: {
'import * as moment from': (id) => {
return 'import moment from'
},
},
include: [reg],
preventAssignment: true,
})
)
},
} }
// 引入外掛 export default ({ mode }) => { return defineConfig({ plugins: [ // ... AntdMomentResolver(), // ... ] }) } ```
九、新增代理
- 安裝path-browserify
bash
pnpm add path-browserify -D
- 新增vite.conf.js配置
js
plugin: [],
// ...
server: {
port: 8000,
//proxy: {
// '/api': {
// target: 'http://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro',
// changeOrigin: true,
// ws: false,
// rewrite: (path) => path.replace(/^\/api/, ''),
// }
//},
},
十、package.json指令碼命令修改
將指令碼命令修改為如下:
json
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
十一、postcss配置
- 安裝外掛
bash
pnpm add postcss autoprefixer -D
十二、新增eslint外掛
- 安裝外掛
bash
pnpm remove eslint eslint-plugin-html eslint-plugin-vue
pnpm add eslint eslint-plugin-html eslint-plugin-vue eslint-config-prettier eslint-plugin-prettier prettier -D
# vite-eslint外掛
pnpm add vite-plugin-eslint -D
- 新增vite.conf.js配置
```js import eslintPlugin from 'vite-plugin-eslint'
export default ({ mode }) => { return defineConfig({ plugins: [ // ... eslintPlugin(), // ... ] }) } ```
十三、在寫有jsx語法的檔案中新增lang="jsx"
```js
```
十四、新增@別名
修改vite.conf.js配置
js
export default ({ mode }) => {
return defineConfig({
resolve: {
// ...
alias: [
{
find: /@\/.+/,
replacement: (val) => {
return val.replace(/^@/, path.resolve(__dirname, './src/'))
},
},
]
},
)
}
十五、靜態檔案引入
- 動態元件引入
```js const modules = import.meta.glob('../views/*/.vue')
const currentRouter {
...
// component: constantRouterComponents[item.component || item.key] || (() => import(/src/views/${item.component}
)),
component: constantRouterComponents[item.component || item.key] || modules[../views/${item.component}.vue
],
...
}
```
-
靜態圖片引入
-
直接
import
圖片```html
```
-
採用
import.meta.globEager
html
html
十六、其他
- 問題:fim.js依賴包引用問題
解決:刪除viser-vue依賴包,可以改用官方G2的封裝庫@antv/g2plot
bash
pnpm remove viser-vue
pnpm add @antv/g2plot
- 問題:ant-design-vue元件List引用問題,List.Item為undefined
解決一:替換程式碼
js
// 替換List元件程式碼,List.Item為undefined
if (source.indexOf('Vue.component(List.Item.name, List.Item);')) {
source = source.replace(
'Vue.component(List.Item.name, List.Item);',
'Vue.component("AListItem", Item);'
)
}
if (source.indexOf('Vue.component(List.Item.Meta.name, List.Item.Meta);')) {
source = source.replace(
'Vue.component(List.Item.Meta.name, List.Item.Meta);',
'Vue.component("AListItemMeta", Item.Meta);'
)
}
解決二:單獨引用List.Item
js
import ListItem from 'ant-design-vue/es/list/Item.js'
遷移後項目地址:GitHub - Seals-Studio/ant-design-vue-pro-vite,歡迎Star~