Vue2 工程优化实践 (webpack5 vite)
背景介绍
工程架构较老,随着项目越来越大,工程本地冷热启动、打包时间都较久,影响了开发的效率。 仅做了工程配置方面的优化,避免伤筋动骨的 Vue 版本升级,达到了较为满意的效果。
成果展示
打包速度优化
-
旧 (182秒)
-
新 (22秒)
本地启动( yarn serve )速度优化
- 旧 无缓存启动 (65秒)
- 旧 有缓存启动 (25.78秒)
- 新 无缓存启动 (1.11秒)
- 新 有缓存启动 (0.81秒)
-
Vite 的启动时间和是否有缓存关系不大 会有波动 都在 1s 左右
-
本地热更新速度优化
- 旧 (4.04秒)
-
如果之前做过类似的代码改动 命中缓存的话 可以降低到 2s 左右
-
- 新 (≈0秒)
具体经历了哪些步骤?
1. 删除冗余的页面、路由、组件、依赖包
工程的完整路由一般存储在服务器中,拉来完整的,和 views
页面目录下进行一一对比,多的列出来,每一个都把文件所有涉及到的路由、组件、依赖包等拎出来,确定是否有其他页面引用到的,没有就全部剔除,有被其他引用到就加入待定名单,待全部冗余页面剔除完毕再看待定名单有没有多的可剔除的内容。
每处理一个页面,就提交一次代码,这样如果发现出现了问题,可以很方便地回滚到上一次提交。
2. webpack 从 4.x 升级到 5.x
webpack 5 不论是编译还是打包速度都有了大幅度的提升
vue-cli 从 4.x 升级到 5.x webpack 亦随之从 4.x 升级到了 5.x
具体步骤
卸载旧版本 vue-cli
npm uninstall @vue/cli -g
安装最新版本 vue-cli
npm install -g @vue/cli@latest
进入到项目升级vue-cli
cd your-project
vue upgrade --next
后续细节处理
会有很多关于 vue-loader 等的报错
很简单
抄 vue-cli 的默认 webpack 配置,问题定能迎刃而解
路径:node_modules/@vue/cli-service/lib/config/base.js
ps: 有问题请留言
原理
- webpack4 根据源代码生成 chunkhash,注释换行的改动就会导致 chunkhash 改变,webpack5 根据源码的具体内容生成 chunkhash,不考虑源码内的注释换行等,chunkhash 不易改变,更容易命中缓存。
- webpack4 的时候 chunkId 和 moduleId 都是自增的,增减模块都会导致缓存不命中,webpack5 优化了 chunkId 和 moduleId 的生成算法
- 新增了硬盘缓存
3. 小的工程配置优化项
alias 加上 noParse
避免解析不需要的文件
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync|lodash|echarts|axios|view-design)$/,
}
配置 cache-loader
// vue.config.js
chainWebpack(config) {
config.module
.rule('vue')
.test(/\.vue$/)
.use('cache-loader')
.loader(require.resolve('cache-loader'))
.end()
.use('vue-loader')
.loader(require.resolve('@vue/vue-loader-v15'))
.options(Object.assign({
compilerOptions: {
whitespace: 'condense'
}
}, {}))
.end()
.end();
}
配置 cdn
// vue.config.js
let cdn = {
css: ['https://cdn01.xxx.com/iview.css'],
js: [
// vue must at first!
'https://cdn01.xxx.com/vue.min.js',
'https://cdn01.xxx.com/vuex.min.js',
// etc...
],
};
chainWebpack(config) {
config.plugin('html').tap((args) => {
args[0].cdn = cdn;
return args;
});
config.plugin('vue-loader')
.use(require('@vue/vue-loader-v15').VueLoaderPlugin);
}
4. 开发环境迁移至 vite
-
保证了打包的稳定性
-
优化热更新至几乎 0秒
-
优化本地启动至十秒内
原理
-
现代浏览器原生支持 ES6 的能力
-
预构建
- 浏览器无法识别
commonjs
的库,将依赖包以es module
规范导出
- 浏览器无法识别
-
速度快
-
依赖不变不执行
-
esbuild (速度极快)
- Go 语言优势 (编译型语言)
- 多进程
-
实践
-
使用官方插件 vite-plugin-vue2
- 将 Vue 2.6 升级至 2.7 (Vite 官方 vue2 插件从 Vue 2.7 开始支持)
-
安装工程依赖
npm i -D vite vite-plugin-commonjs @vitejs/plugin-vue2
-
在 package.json 添加
vite
启动指令
{
"scripts": {
"vite": "NODE_ENV=development vite"
}
}
-
创建
vite.config.js
文件于项目根目录-
将 src 下不符合 esModule 规范的代码转换成符合的
- vite-plugin-commonjs
-
处理 process 在 Vite 工程中无法识别的问题
-
export default defineConfig(({ mode }) => {
const envPrefix = ['VUE'];
const env = loadEnv(mode, process.cwd(), envPrefix);
const define = {
'process.env.NODE_ENV': '"development"',
'VUE_APP_ENV': '"development"',
'process.env.VUE_APP_BATCH_DELIVER_TEMPLATE': '"https://xxx.oss-cn-shanghai.aliyuncs.com/prod/template/XLS/xxx.xlsx"'
};
for (const [key, value] of Object.entries(env)) {
define[`process.env.${key}`] = `"${value}"`;
}
return {
define,
};
}
- 处理动态引用在 Vite 工程支持不友好的问题
import dynamicImport from 'vite-plugin-dynamic-import';
plugins: [
dynamicImport(),
],
- 处理本地服务器代理
server: {
open: true,
port: config.port,
proxy: {
'/store': {
target: 'http://dev.xxx.net', // 测试环境
changeOrigin: true,
logs: console,
secure: false,
},
},
}
- 综合如下
import vue from '@vitejs/plugin-vue2';
import { defineConfig, loadEnv } from 'vite';
import config from './src/config/index';
import commonjs from 'vite-plugin-commonjs';
import dynamicImport from 'vite-plugin-dynamic-import';
const path = require('path');
const resolve = (dir) => {
return path.join(__dirname, dir);
};
export default defineConfig(({ mode }) => {
const envPrefix = ['VUE'];
const env = loadEnv(mode, process.cwd(), envPrefix);
const define = {
'process.env.NODE_ENV': '"development"',
'VUE_APP_ENV': '"development"',
'process.env.VUE_APP_BATCH_DELIVER_TEMPLATE': '"https://xxx.oss-cn-shanghai.aliyuncs.com/prod/template/XLS/xxx.xlsx"'
};
for (const [key, value] of Object.entries(env)) {
define[`process.env.${key}`] = `"${value}"`;
}
return {
define,
root: './',
publicDir: 'public',
base: './',
mode: 'development',
plugins: [
vue(),
commonjs(),
dynamicImport(),
],
resolve: {
alias: {
'@': resolve('src'),
},
extensions: [
'.vue',
'.js',
],
},
css: {
preprocessorOptions: {
scss: {
// 两种方式都可以
additionalData: '@import "@/styles/common.scss";'
},
less: {
javascriptEnabled: true,
},
}
},
server: {
open: true,
port: config.port,
proxy: {
'/store': {
target: 'http://dev-gateway.xxx.net', // 测试环境
changeOrigin: true,
logs: console,
secure: false,
},
},
}
};
});
-
创建
index.html
于项目根目录-
抄
public/index.html
文件的-
剔除
webpack
特有的转义语法 -
html 文件中引用的文件目录记得相应更新
-
在 index.html 文件中引入
src/main.js
文件<script type="module" src="./src/main.js"></script>
-
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width"> <link rel="icon" href="./public/logo.ico" type="image/x-icon" /> <title>store</title> <meta name="keywords" content="keywords" /> <meta name="description" content="description" /> </head> <body> <script type="module" src="./src/main.js"></script> <script src="./public/config.js"></script> <noscript> <strong >We're sorry doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"> <div class="page-loading-wrap"> <div class="half-circle-spinner"> <div class="circle circle-1"></div> <div class="circle circle-2"></div> </div> <h4 style="margin-top: 20px">正在加载资源...</h4> </div> </div> </body> </html>
-
接下来就是细节不兼容处理
-
旧版本
postcss
不兼容,升级postcss
版本-
{ "devDependencies": { "postcss": "^8.4.21" } }
-
结语
vite 用于本地开发真的很香,可以大大提升开发效率。 仅用于本地开发的话,还可以避免从 webpack 迁移到 rollup 打包带来的风险。 一开始配置遇到编译/运行错误,查下错误原因解决即可,虽然工程很大,但是改起来非常顺畅。(一般一小时内解决,比想象中快很多 ;)
转载自:https://juejin.cn/post/7206604884056539173