全网最硬核的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相关依赖
  1. 删除@vue和babel相关
    { "@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", }

  2. 删除loader(webpack插件)和webpack
    { "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", }

  3. 删除babel.conf.js和jsconfig.json
  4. 安装pnpm工具
pnpm是快速的,节省磁盘空间的包管理工具
npm i -g pnpm # 淘宝源 pnpm config set registry https://registry.npm.taobao.org pnpm config set disturl https://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 https://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
pnpm add vite vite-plugin-vue2 -D

四、在根目录下新建vite.conf.js
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标签中新增如下:

  • 替换htmlWebpackPlugin插件注入的变量
    htmlWebpackPlugin是webpack插件,所以不能再使用了,vite提供了vite-plugin-html插件来向index.html注入变量
    1. 安装vite-plugin-html
      pnpm add vite-plugin-html -D

    2. 修改vite.config.js,添加配置
    plugins: [ // ... createHtmlPlugin({ minify: true, inject: { data: { title: 'Ant Design Pro', cdn: { css: [], js: [ '//cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js', '//cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js', '//cdn.jsdelivr.net/npm/vuex@3.1.1/dist/vuex.min.js', '//cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js' ] } } } }), // ... ]

    1. 修改index.html
      • 修改title
        - 锐客网

      • 修改css和js引入

六、环境变量更换
出于安全考虑,vite只能识别以VITE_开头的环境变量了,原VUE_环境变量不生效了,同时,也不能使用process.env.xxx来读取环境变量了。需要修改vite.conf.js配置,手动添加process.env.xxx环境变量
  • 修改vite.conf.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插件
# 注意本插件必须采用1.4.1版本,不能采用最新版2.0.0 pnpm add vite-plugin-style-import@^1.4.1 -D

  1. 增加vite.conf.js配置
    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. 安装依赖包
    pnpm add rollup@">=1.20.0 <2.0.0 || >=2.0.0 <3.0.0" -D pnpm add @rollup/plugin-replace -D

  2. 修改vite.conf.js配置
import path from 'path-browserify' import fs from 'fs' import replace from '@rollup/plugin-replace'// 参考vite-plugin-antdv1-momentjs-resolver插件,修改正则表达式,兼容Windows路径 // https://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
    pnpm add path-browserify -D

  2. 添加vite.conf.js配置
    plugin: [], // ... server: { port: 8000, //proxy: { //'/api': { //target: 'https://mock.ihx.me/mock/5baf3052f7da7e07e04a5116/antd-pro', //changeOrigin: true, //ws: false, //rewrite: (path) => path.replace(/^\/api/, ''), //} //}, },

十、package.json脚本命令修改
将脚本命令修改为如下:
"scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" },

十一、postcss配置
  1. 【全网最硬核的Ant-Design-Vue从Vue-cli迁移至Vite】安装插件
    pnpm add postcss autoprefixer -D

十二、添加eslint插件
  1. 安装插件
    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

  2. 添加vite.conf.js配置
    import eslintPlugin from 'vite-plugin-eslint'export default ({ mode }) => { return defineConfig({ plugins: [ // ... eslintPlugin(), // ... ] }) }

十三、在写有jsx语法的文件中添加lang="jsx"

十四、添加@别名
修改vite.conf.js配置
export default ({ mode }) => { return defineConfig({ resolve: { // ... alias: [ { find: /@\/.+/, replacement: (val) => { return val.replace(/^@/, path.resolve(__dirname, './src/')) }, }, ] }, ) }

十五、静态文件引入
  1. 动态组件引入
    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`], ... }

  2. 静态图片引入
    • 直接import图片

    • 采用import.meta.globEager


    ### 十六、其他

  3. 问题:fim.js依赖包引用问题
    解决:删除viser-vue依赖包,可以改用官方G2的封装库@antv/g2plot
    pnpm remove viser-vue pnpm add @antv/g2plot

  4. 问题:ant-design-vue组件List引用问题,List.Item为undefined
    解决一:替换代码
    // 替换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

    推荐阅读