全網最硬核的Ant-Design-Vue從Vue-cli遷移至Vite

語言: CN / TW / HK

一、前言

眾所周知,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相關依賴

  1. 刪除@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", }

  1. 刪除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", }

  1. 刪除babel.conf.jsjsconfig.json

  2. 安裝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 ```

三、安裝最新版vitevite-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注入變數

  1. 安裝vite-plugin-html

    bash pnpm add vite-plugin-html -D

  2. 修改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' ] } } } }), // ... ]

  1. 修改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按需引入

  1. 安裝vite-plugin-style-import外掛

```bash

注意本外掛必須採用1.4.1版本,不能採用最新版2.0.0

pnpm add [email protected]^1.4.1 -D ```

  1. 增加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

  1. 安裝依賴包

bash pnpm add [email protected]">=1.20.0 <2.0.0 || >=2.0.0 <3.0.0" -D pnpm add @rollup/plugin-replace -D

  1. 修改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(), // ... ] }) } ```

九、新增代理

  1. 安裝path-browserify

bash pnpm add path-browserify -D

  1. 新增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配置

  1. 安裝外掛

bash pnpm add postcss autoprefixer -D

十二、新增eslint外掛

  1. 安裝外掛

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

  1. 新增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/')) }, }, ] }, ) }

十五、靜態檔案引入

  1. 動態元件引入

```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], ... }

```

  1. 靜態圖片引入

  2. 直接import圖片

    ```html

    ```

  3. 採用import.meta.globEager

    htmlhtml

十六、其他

  1. 問題:fim.js依賴包引用問題

解決:刪除viser-vue依賴包,可以改用官方G2的封裝庫@antv/g2plot

bash pnpm remove viser-vue pnpm add @antv/g2plot

  1. 問題: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~