目录
- 前言
- 迁徙前后比照
- 迁徙流程
- 迁徙业务代码到vite我的项目
- 我的项目开发阶段报错解决
- 我的项目打包阶段解决
- 总结
一. 前言
公司有个特地大保护工夫长的后盾管理系统,应用的是vue2和webpack3,尽管配置了很多编译优化,但启动和开发热更新速度仍然很慢,极大的影响了开发效率,于是筹备迁徙vite2来优化,当初已迁徙降级,来复盘记录下过程,至于vite速度快于webpack的起因,曾经有很多文章讲的很明确,这里只记录下迁徙过程和遇到的问题。
二. 迁徙前后比照
比照 | 迁徙前webpack3 | 迁徙后vite2 |
---|---|---|
启动开发模式 | 40秒 | 3秒之内 |
热更新 | 6秒+ | 1秒之内 |
打包构建(vite不做低版本浏览器兼容) | 2分30秒 | 40秒 |
打包构建(vite做低版本浏览器兼容) | 2分30秒 | 1分05秒 |
三. 迁徙流程
- 先创立新的vite我的项目
- 新版vite我的项目默认是反对vue3的,须要把vue改成vue2版本后配置vite-plugin-vue2插件来反对vue2
- 把我的项目代码改成vue2写法,确保新vite我的项目能够失常运行vue2
- 把原webpack我的项目生产环境依赖复制到vite我的项目,剔除掉webpack相干的插件依赖
- 复制原我的项目src文件代码和其余业务相干代码到新vite我的项目。
- 新vite我的项目配置开发环境启动命令,依据报错信息来进行调整。
- 在测试开发和打包环境都没问题后,替换原先的我的项目。
四. 迁徙业务代码到vite我的项目
4.1 创立新的vite我的项目
关上vite官网,依照官网提醒创立新的vite我的项目(因为原先我的项目没有用ts,所以创立我的项目不选ts版本,包管理工具也仍然抉择是npm)。
npm init vite@latest my-vue-app -- --template vue
创立实现后,应用vs code关上,关上命令行,执行npm i装置依赖
npm i
装置依赖实现后,应用npm run dev启动我的项目
npm run dev
启动实现后,关上我的项目地址http://localhost:3000/
此时根本的vite2+vue3我的项目曾经启动胜利了,但此时vite反对的还是vue3版本的,咱们须要让vite反对vue2版本。
4.2 配置vite反对vue2
此时关上vite.config.js,外面的代码为
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'// https://vitejs.dev/config/export default defineConfig({ plugins: [vue()]})
@vitejs/plugin-vue插件是对vue3语法做反对,如果要反对vue2,须要用vite-plugin-vue2
第一步,从vite中删除 @vitejs/plugin-vue配置,从package.json文件中也删除。
npm uninstall @vitejs/plugin-vue -D
第二步,装置vite-plugin-vue2依赖
npm install vite-plugin-vue2 -D
第三步,在vite.config.js文件配置vite-plugin-vue2
import { defineConfig } from 'vite'import { createVuePlugin } from "vite-plugin-vue2";// https://vitejs.dev/config/export default defineConfig({ plugins: [createVuePlugin()]})
第四步,批改vue版本由3改为2版本
npm install vue@2 -S
第五步, 批改main.js,创立根vue实例写法改为vue2写法
import Vue from 'vue'import App from './App.vue'new Vue({ render: h => h(App),}).$mount('#app')
第六步,批改main.js实现后,批改App.vue文件代码为vue2格局代码
<template>vue <h1>{{title}}</h1></template><script>export default { name: 'App', data() { return { title: 'webpack3迁徙vite2' } }}</script>
此时package.json, vite.config.js, main.js, App.vue代码别离为
执行npm run dev,即可看到启动胜利,代表此时vite曾经反对vue2语法了,能够开始我的项目迁徙工作了。
4.3 复制原我的项目业务代码
第一步,复制原我的项目动态目录static下文件到vite我的项目public文件夹下
第二步,复制原我的项目index.html文件内容替换vite我的项目的index.html内容(留神本地动态资源引入的门路)替换后须要在body完结标签前增加
<script type="module" src="/src/main.js"></script>
<!DOCTYPE html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>经营平台</title> <link rel="icon" href="/favicon.ico" type="image/x-icon"> <link href="https://unpkg.com/ionicons@4.2.2/dist/css/ionicons.min.css" rel="stylesheet"></head><body> <div id="app"></div> <!-- built files will be auto injected --> <script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script> <script type="module" src="/src/main.js"></script></body></html>
第三步, 复制package.json中生产环境依赖到新vite我的项目,去除webpack相干配置依赖,此时最新的vite代码
{ "name": "my-vue-app", "private": true, "version": "0.0.0", "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, "dependencies": { "vue": "^2.6.14", "axios": "^0.18.0", "babel-polyfill": "^6.26.0", "dayjs": "^1.7.8", "dingtalk-jsapi": "^2.7.3", "element-ui": "^2.13.1", "good-storage": "^1.0.1", "js-base64": "^2.4.9", "moment": "^2.23.0", "nprogress": "^0.2.0", "qs": "^6.5.2", "sockjs-client": "^1.3.0", "stompjs": "^2.3.3", "swiper": "^4.3.5", "v-viewer": "^1.2.1", "vue-router": "^3.0.1", "vue-virtual-scroller": "^1.0.10", "vuex": "^3.0.1" }, "devDependencies": { "vite": "^2.9.2", "vite-plugin-vue2": "^2.0.0" }}
第四步,复制原我的项目src业务文件代码,间接替换vite我的项目src文件,此时整体我的项目构造如下
4.4 配置vite的我的项目环境变量
因为原我的项目应用了cross-env来设置环境变量,为了能够失常启动我的项目,须要在vite外面也配置下环境变量
第一步,装置cross-env
npm install cross-env -D
第二步,配置scripts脚步命令,应用cross-env来设置环境变量BASE_ENV(这一步要按本人我的项目状况来配置)
"scripts": { "dev:dev": "cross-env BASE_ENV=development vite", "dev:test": "cross-env BASE_ENV=test vite", "dev:pre": "cross-env BASE_ENV=pre vite", "dev:prod": "cross-env BASE_ENV=production vite", "build:dev": "node node_modules/esbuild/install.js && cross-env BASE_ENV=development vite build", "build:test": "node node_modules/esbuild/install.js && cross-env BASE_ENV=test vite build", "build:pre": "node node_modules/esbuild/install.js && cross-env BASE_ENV=pre vite build", "build:prod": "node node_modules/esbuild/install.js && cross-env BASE_ENV=production vite build", "preview": "vite preview"}
- 打包增加node node_modules/esbuild/install.js,是用来解决esbuild装置时报错的bug相干issue
- 之所以环境变量没有应用NODE_ENV,是因为很多第三方包都应用NODE_ENV来判断开发环境和打包环境,为了不影响,采纳新加一个环境变量的形式
第三步, 配置vite.config.js,使vite在我的项目外面注入环境变量
只是应用cross-env设置环境变量的话,我的项目外面是拜访不到的,须要配置一下vite的define配置,能力拜访到,相似于webpack的DefinePlugin插件性能
import { defineConfig } from 'vite'import { createVuePlugin } from "vite-plugin-vue2";// https://vitejs.dev/config/export default defineConfig({ plugins: [createVuePlugin()], define: { /** 我的项目环境变量 **/ 'process.env.BASE_ENV': JSON.stringify(process.env.BASE_ENV) },})
此时后期筹备工作都曾经实现,能够开始启动我的项目了,必定会有很多报错,须要依据报错信息来进行调整
五. 我的项目开发阶段报错解决
先依据下面配置好的命令,启动开发模式
npm run dev:dev
5.1 第一个报错,The following dependencies are imported but could not be resolved:
由提示信息很容易能够看出,是因为原我的项目应用webpack配置了别名,但新vite我的项目未配置别名造成的,咱们须要在vite中增加别名配置
依据vite别名规定,vite.config.js增加配置,把@/指向src目录
import { defineConfig } from 'vite'import { createVuePlugin } from "vite-plugin-vue2";// https://vitejs.dev/config/export default defineConfig({ plugins: [createVuePlugin()], define: { /** 我的项目环境变量 **/ 'process.env.BASE_ENV': JSON.stringify(process.env.BASE_ENV) }, resolve: { /** 增加alias规定 **/ alias: [ { find: '@/', replacement: '/src/' } ], },})
增加后再次重启我的项目,呈现第二个报错
5.2 第二个报错, Failed to resolve import "./App" from "src/main.js
报错是因为引入App组件的时候没有带文件后缀 .vue, 所以未找到,此时有两种解决方案
- 手动增加 .vue后缀,然而我的项目这么宏大,很多中央都没有带后缀,全副改必定不容易。
- 配置vite.config.js的extensions字段,来增加主动查找文件扩展名后缀。
采纳第二种vite配置extensions扩展名,在vite.config.js外面增加resolve.extensions配置
import { defineConfig } from 'vite'import { createVuePlugin } from "vite-plugin-vue2";// https://vitejs.dev/config/export default defineConfig({ plugins: [createVuePlugin()], define: { /** 我的项目环境变量 **/ 'process.env.BASE_ENV': JSON.stringify(process.env.BASE_ENV) }, resolve: { /** 增加alias规定 **/ alias: [ { find: '@/', replacement: '/src/' } ], /** 临时先加.vue, .js, .json **/ extensions: [".vue", ".js", ".json"], },})
增加后再次重启我的项目,呈现第三个报错
5.3 第三个报错, dependency "sass" not found. Did you install it
由报错信息可知,是因为我的项目外面应用了sass,less,然而没有对应的解析配置,须要增加一下vite解析sass,less的配置
装置vite中解析sass, less插件
npm install less sass -D
在vite中只须要装置sass,less插件就能够了,vite会主动应用该插件去解决sass,less文件
增加后再次重启我的项目,呈现第四个报错
5.4 第四个报错, Can't find stylesheet to import.
看报错信息是在配置element-ui自定义主题色的时候,在element-variables.scss文件中应用 @import了element-ui的主题文件,应用~前缀,而vite解析不了,所以没有找到对应的文件。
须要把前缀~去掉,间接去援用node_modules下的主题款式文件即可,然而因为element-ui应用calc语法,在sass2.0.0版本会删除对该办法的反对,所以控制台会报正告:
Deprecation Warning: Using / for division outside of calc() is deprecated and will be removed in Dart Sass 2.0.0.
不影响失常我的项目运行,如果要解决的话,升高sass的版本就能够了,目前sass版本是1.51.1,手动降版本
npm install sass@1.30.0 -D
增加后再次重启我的项目, 控制台就不会呈现正告了。
5.5 第五个报错, require is not defined
这次启动我的项目后,命令行没有报错了,而后关上浏览器,发现页面白屏,关上控制台看到控制台报错
token.js:18 Uncaught ReferenceError: require is not defined at token.js
关上对应的token.js应用reuire引入了一张图片,而vite不反对require,咱们须要换一种引入形式来引入图片。
有三种计划:
1. 第一种是采纳import/from来引入,这种形式适宜图片和所有模块,也是最符合规范,利用tree-shrink的。2. 第二种是间接把图片提前压缩解决后放在public文件下,就能够通过根门路/xxx.png来拜访到了。3. 第三种应用vite提供的import.meta.glob()办法,但该办法返回的是异步的,适宜配置懒加载动静路由。
这里我采纳的是第二种形式,把boy.png放在public目录下,require引入改成固定字符串 '/boy.png' ,这样打包时就不必对图片做解决了,能够进步打包速度。
全局搜寻一下require,把应用require引入图片的中央都改成绝对路径或者import/from引入。
批改后再次重启我的项目,这次批改后命令后仍然没有报错,关上浏览器后页面呈现了第六个报错
5.6 第六个报错, Failed to resolve import ‘../xxx.png’.
依据提示信息找到对应的文件,能清晰的看到报错起因,是因为页面外面应用img标签,src应用的相对路径
<img src="../../../static/userContent.png"">
static目录曾经被public目录替换掉了,所以对于图片咱们还是间接压缩解决后放的public文件夹,我的项目内应用绝对路径来引入,解决完后变成了
<img src="/userContent.png"">
其余页面有相似状况的能够用同样的形式来解决。
批改后再次重启我的项目,这次批改后命令后仍然没有报错,关上浏览器后页面能够失常显示登录页面了,然而登录后页面又呈现了第7个报错。
5.7 第七个报错, require引入动静异步组件问题.
看报错信息,这次和路由有关系,找到对应文件cache.js,发现页面应用require来引入动静路由组件了。
解决方案,采纳vite提供的import.meta.glob办法,写法如下
const modules = import.meta.glob('./../../pages/**/*.vue');function getBaseRouterWrap(item,PathMap,parentItem) { return { path: item.url, name: item.routerName, component: modules[`./../../${PathMap[item.routerName]}.vue`], meta: { parentName:parentItem ? parentItem.routerName : null, title: item.name, tag: true, icon: item.ico || '', needLogin: true, count: item.count, show: item.show } }}
看一下const modules = import.meta.glob('./../../pages/**/**.vue');的返回后果
import.meta.glob办法会把门路下所有查问到的文件以门路为key,异步返回内容为value放到一个对象外面,应用的时候依据对于的文件名称引入,内容是 () => import('xxx.vue') 异步引入的,正好合乎vue-router组件懒加载规定。
批改后再次重启我的项目,这次批改后命令后仍然没有报错,关上浏览器后页面能够失常登录跳转页面了,然而跳转后页面又呈现了第8个报错。
5.8 第八个报错, ‘xxx.less’ wasn't found..
发现还是因为门路的问题,有两种解决形式:
1. 第一种将所有的~@/改成咱们曾经配置到别名@/。2. 新配置一个别名让~@/也指向src目录。
这里采纳的第二种形式,比较简单,只改一个中央就好了。
批改后再次重启我的项目,这次批改后命令后仍然没有报错,关上浏览器后页面能够失常跳转了,切换多个页面都没有发现问题,测试一下热更新速度,在某个页面进行测试的时候发现,每次热更新状态都会重置,查看文件加载状况,发现又从新引入了main.js。
5.9 第九个报错, 热更新后触发从新实例化vue流程
在查找起因后,发现在main.js外面定义了退出登录的办法,而在触发热更新的页面从main.js外面引入了该办法,所以每次触发热更新,从新申请该页面 .vue文件时,也会触发从新加载main.js,从而引起该问题的产生,解决办法,把main.js裸露的办法独自抽离到其余js文件外面,抽离后再测试就没问题了。
至此,开发阶段呈现的报错就都曾经解决了。
六. 我的项目打包阶段解决
6.1 解决我的项目兼容低版本浏览器
vite打包后默认指标浏览器是指向现带浏览器,就是反对es module的浏览器,可是在很多时候咱们须要兼容低版本的浏览器,vite官网为咱们提供了开箱即用的插件@vitejs/plugin-legacy
先装置插件
npm install @vitejs/plugin-legacy -D
在vite.config.js的plguins插件外面增加
import legacy from '@vitejs/plugin-legacy'legacy({ targets: ['ie >= 9'], additionalLegacyPolyfills: ['regenerator-runtime/runtime'],})
targets要依据本人我的项目状况来配置,插件还有很多其余的配置,能够看插件文档
6.2 解决css加前缀问题
原我的项目配置了pocss-loader来打包时主动加css前缀来兼容低版本浏览器,所以迁徙到vite后也须要解决下,在vite中能够采纳autoprefixer来实现,装置:
npm install autoprefixer -D
在vite.config.js的css.postcss.plugins外面增加autoprefixer插件,因为该插件默认只反对common.js,所以要用require引入,前面配置要反对的指标浏览器。
css: { postcss: { plugins: [ require('autoprefixer')({ overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 9', '> 1%'], grid: true, }), ] } }
配置实现后,再次打包后,就能够看到css曾经加上了前缀。
七. 总结
下面的实现后,打包就也没问题了,就能够连贯我的项目git或者笼罩复制到原我的项目中,提交到测试环境开始构建了。
当初vite的生态也趋于变的成熟,曾经能够满足于大部分业务场景了,不过在迁徙前还是尽量要做下调研,看目前vite生态是否满足本我的项目中一些定制化或者非凡的场景,比方微前端,electron反对等。
本文记录了在本我的项目迁徙过程中遇到的问题,遇到的问题必定只是webpack迁徙vite很小的一部分问题,当前在迁徙其余我的项目时候遇到新的问题也会补充进来。
本次迁徙最终vite配置
import { defineConfig } from "vite";import { createVuePlugin } from "vite-plugin-vue2";import CompressionWebpackPlugin from 'vite-plugin-compression'import legacy from '@vitejs/plugin-legacy'export default defineConfig({ plugins: [ /** 反对vue2 **/ createVuePlugin(), /** gzip压缩 **/ CompressionWebpackPlugin({ algorithm: 'gzip', threshold: 10240 //只有大小大于该值的资源会被解决。默认值是 10k }), /** 配置浏览器兼容 **/ legacy({ targets: ['ie >= 9'], additionalLegacyPolyfills: ['regenerator-runtime/runtime'] }) ], build: { chunkSizeWarningLimit: 2000, terserOptions: { compress: { drop_console: true, drop_debugger: true } }, brotliSize: false, }, /** 为我的项目注入环境变量 **/ define: { 'process.env.BASE_ENV': JSON.stringify(process.env.BASE_ENV) }, resolve: { /** 引入文件未带后缀时,顺次查找数组外面配置的后缀文件 **/ extensions: [".vue", ".js", ".json"], /** 配置alias别名 **/ alias: [ { find: '@/', replacement: '/src/' } ], }, /** css主动加前缀 **/ css: { postcss: { plugins: [ require('autoprefixer')({ overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 9', '> 1%'], grid: true, }), ] } }, server: { host: "0.0.0.0", },});
参考资料:
vite官网:https://vitejs.cn