6年的老项目迁移vite2,提速几十倍,真香
背景
gou系统又老又大又乱,每一次的需求开发都极其难受,启动30|40几秒勉强能接受吧,毕竟一天也就这么一回,但是
HMR
更新也要好几秒实在是忍不了,看到了vite2就看到了曙光!盘它
先看看vue-cli3的启动编译吧...
- 该项目为内部运营管理系统,年龄6岁+
- 基于
vue2+elementui
,2年入职时将vue-cli2
升级到了vue-cli3
,2年后的今天迫不及待的的奔向vite2
了 - 仅迁移开发环境(我的痛点只是开发环境,对于生产环境各位自行考虑)
痛点分析
实质上是对webpack
工作原理的分析,webpack
在开发环境的工作流大致如下(个人见解不喜勿喷):
查找入口文件 => 分析依赖关系 => 转化模块函数 => 打包生成bundle => node服务启动
所以随着项目越来越大,速度也就越来越慢...
至于HMR
也是同理,只不过HMR
是将当前文件作为入口,进行rebuild
,涉及的相关依赖都需要重载
为什么是Vite
- vite是基于
esm
实现的,主流浏览器已支持,所以不需要对文件进行打包编译 - 项目启动超快(迁移后简单的概算数据是从30s 提升到 1s。30倍?3000%?一点都不夸张...)
- 还是基于
esm
,HMR
很快,不需要编译重载,速度可以用一闪而过来形容...
vite
大致工作流:
启动服务 => 查找入口文件(module script) => 浏览器发送请求 => vite劫持请求处理返回文件到浏览器
开盘,踏上迁移之路
安装相关npm包
npm i vite vite-plugin-vue vite-plugin-html -D
vite-plugin-vue
,用于构建vue
,加载jsx
vite-plugin-html
,用于入口文件模板注入
在
package.json
文件中,新增一个vite
启动命令:"vite": "cross-env VITE_NODE_ENV=dev vite"
根目录新建
vite.config.js
文件将
public
下的index.html
复制一份到根目录仅迁移开发环境,public下仍然需要index.html,支持开发环境下vite和webpack两种模式
修改根目录下
index.html
(vite启动的入口文件,必须是根目录)<% if (htmlWebpackPlugin.options.isVite) { %>
<script type="module" src="/src/main.js"></script>
<%}%>htmlWebpackPlugin在vite.config.js注入,isVite用于标识是否是vite启动
import { injectHtml } from 'vite-plugin-html';
export default defineConfig({
plugins:[
injectHtml({
injectData: {
htmlWebpackPlugin: {
options: {
isVite: true
}
},
title: '运营管理平台'
}
})
]
})完整
vite.config.js
配置import { defineConfig } from 'vite'
import path from 'path'
import fs from 'fs'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml, minifyHtml } from 'vite-plugin-html'
import dotenv from 'dotenv'
try {
// 根据环境变量加载环境变量文件
const VITE_NODE_ENV = process.env.VITE_NODE_ENV
const envLocalSuffix = VITE_NODE_ENV === 'dev' ? '.local' : ''
const file = dotenv.parse(fs.readFileSync(`./.env.${VITE_NODE_ENV}${envLocalSuffix}`), {
debug: true
})
for (const key in file) {
process.env[key] = file[key]
}
} catch (e) {
console.error(e)
}
const resolve = (dir) => {
return path.join(__dirname, './', dir)
}
export default defineConfig({
root: './',
publicDir: 'public',
base: './',
mode: 'development',
optimizeDeps: {
include: []
},
resolve: {
alias: {
'vendor': resolve('src/vendor'),
'@': resolve('src'),
'~component': resolve('src/components')
},
extensions: [
'.mjs',
'.js',
'.ts',
'.jsx',
'.tsx',
'.json',
'.vue'
]
},
plugins: [
createVuePlugin({
jsx: true,
jsxOptions: {
injectH: false
}
}),
minifyHtml(),
injectHtml({
injectData: {
htmlWebpackPlugin: {
options: {
isVite: true
}
},
title: '运营管理平台'
}
})
],
define: {
'process.env': process.env
},
server: {
host: '0.0.0.0',
open: true,
port: 3100,
proxy: {}
}
})相关配置会在下文遇到的问题中做具体描述
迁移过程中遇到的问题
Uncaught SyntaxError: The requested module 'xx.js' does not provide an export named 'xx'
本人遇到的分以下两类情况:
a. 一个模块只能有一个默认输出,导入默认输出时,
import
命令后不需要加大括号,否则会报错处理方式:将原先
{}
导入的keys
,改成导入默认key
,es6
解构赋值-import { postRedeemDistUserUpdate } from '@/http-handle/api_types'
+import api_types from '@/http-handle/api_types'
+const { postRedeemDistUserUpdate } = api_typesb. 浏览器仅支持
esm
,不支持cjs
,需要将cjs
改为esm
(看了网文有通过cjs2esmodule
处理的,但是本人应用有些场景是报错的,最后就去掉了)处理方式:不推荐使用
cjs2esmodule
,手动将module.exports
更改为export
-module.exports = {
+export default {.vue
文件扩展,最新版本的vite
貌似已支持extensions
添加.vue
,不过还是推荐手动添加下后缀。(骚操作:正则匹配批量添加)Uncaught ReferenceError: require is not defined
浏览器不支持cjs
处理方式:
require
引用的文件都需要修改为import
引用vite启动,页面空白
处理方式:注意入口文件index.html,需要放置项目根目录
vite
环境下默认没有process.env
,可通过define
定义全局变量vue-cli
模式下,环境变量都是读取根目录.env
文件中的变量,那么vite
模式下是否也可以读取.env
文件中的变量最终注入到process.env
中呢?这样不就可以两种模式共存了么?成本变小了么?
处理方式:
- 安装环境变量加载工具:
dotenv
npm i dotenv -D
自定义全局变量
process.env
vite.config.js
中配置
define: {
'process.env': {}
}加载环境变量,并添加到
process.env
vite.config.js
中配置因为仅迁移开发环境,所以我这里默认是读取.local文件。
VITE_NODE_ENV是在启动时通过cross-env注入的
import dotenv from 'dotenv'
try {
const VITE_NODE_ENV = process.env.VITE_NODE_ENV
const envLocalSuffix = VITE_NODE_ENV === 'dev' ? '.local' : ''
const file = dotenv.parse(fs.readFileSync(`./.env.${VITE_NODE_ENV}${envLocalSuffix}`), {
debug: true
})
console.log(file)
for (const key in file) {
process.env[key] = file[key]
}
} catch (e) {
console.error(e)
}
jsx
支持vite.config.js
中配置plugins: [
createVuePlugin({
jsx: true,
jsxOptions: {
injectH: false
}
})webpack中
require.context
方法,在vite
中使用import.meta.glob
替换
现存问题
项目中导入/导出的功能,是纯前端实现的
require('script-loader!file-saver')
require('script-loader!@/vendor/Blob')
由于以上文件目前不支持import
引入,webpack
下是通过script-loader
加载挂载到全局的,vite
环境下未能解决。需要导入导出功能时只能切换到vue-cli
模式启动服务...
如果各位大大有方案,麻烦指导指导~,实在是不想回到webpack
开发了...
最后
总体迁移上并没有遇到什么疑难杂症,迁移成本还是不大的,实操1-2天,性价比很高哦,我这个项目按数据看就是几十倍的启动提效,几倍的HMR提效...各位可以在内部系统上做下尝试。
链接:https://juejin.cn/post/7005479358085201957