前言
首先我们需要确认一点,不管是webpack
也好,vite
也好,rollup
也好,他们都只是构建工具,所以这一章我们就来探索一下项目在构建时的策略所能带来的性能优化。想学习webpack
的同学,请戳 >>> 重学webpack系列(九) -- webpack的高级特性与前端性能优化
分包策略
- 背景:在项目开发中,我们肯定是会去引用第三方包里面的某个或多个方法,但是打包之后,我们会发现,三方包的代码与业务代码会糅杂在一起,因为三方库代码一般是永久不变的,而业务代码可能会经常变化,那么每一次打包就会重新打包所有文件,这将会造成浏览器缓存失效。为什么浏览器缓存会失效?因为每一次重新打包之后文件名会变化,文件名变化之后,浏览器会重新请求资源包,所以需要分包策略来实现资源包的拆分,以达到浏览器只对有过更改的资源包进行请求。
- 示例:我们以lodash库作为示例。
import {debounce} from 'lodash'; // 导入debounce
const list = [1,2,3];
function abc(list){
list.forEach(ele=>{
console.log(ele)
})
}
debounce(abc(list), 2000) // 测试代码而已
根据上面的图,我们看到我只用了
debounce
一个方法,他却把整个lodash
一起打包了,所以我们需要把lodash
包拆出来单独打包。
- 实践:
vite
给我们提供了一个build
配置,来实现分包。
export default defineConfig({
...
build:{ // 生产环境的配置
rollupOptions:{ // 给rollup的配置
output:{ // 输出
assetFileNames:"[name]-[hash].[ext]", // 文件名处理
manualChunks:(id)=>{ // 分包
if(id.indexOf('node_modules') !== -1){
return 'vendor' // 如果参与打包的模块含有node_modules里面的模块,那么就打包到vendor里面
}
}
}
},
assetsInlineLimit:"1024", // 大于1024kb资源,打包成base64,
outDir:"build",
assetsDir:"static",
minify:false
},
})
结果是产生了一个vendor
来专门存放lodash
库的代码。
我们的业务代码只会放进index-*.js
中。
比如我们再去添加其他的库看看打包效果,添加如下代码:
import $ from 'jquery';
const arr = $.merge([1,2], [3,4])
console.log('arr////',arr);
明显可见jQuery
被打包进了vendor
中,业务代码进了index-*.js
。
所以我们可以在浏览器端通过更改文件来测试一下。
- 首次刷新:
- 更改
testJQuery.js
之前:
- 更改
testJQuery.js
之后:
所以这就实现了我们分包策略,能够很大程度的去减少网络请求资源所需要的时间,提高收益。
注意:如果你不想写这么“麻烦”的配置,你可以使用splitVendorChunkPlugin
插件来代替上面的工作,他们能够实现一模一样的功能。
// vite.base.config.js
import { splitVendorChunkPlugin } from 'vite'
export default defineConfig({
plugins: [splitVendorChunkPlugin()],
})
多入口打包策略
和webpack
一样,vite
也具有多入口打包的策略,vite
提供了一个input
配置项,能够指定多个入口进行打包,比如:
```js
export default defineConfig({
...
build:{ // 生产环境的配置
rollupOptions:{ // 给rollup的配置
input:{ // 配置入口,默认index.html为入口
dev:path.resolve(__dirname, 'dev.js'),
prod:path.resolve(__dirname, 'prod.html'),
index:path.resolve(__diename, 'index.html')
},
output:{ // 输出
assetFileNames:"[name]-[hash].[ext]", // 文件名处理
manualChunks:(id)=>{ // 分包
if(id.indexOf('node_modules') !== -1){
return 'vendor' // 如果参与打包的模块含有node_modules里面的模块,那么就打包到vendor里面
}
}
}
},
assetsInlineLimit:"1024", // 大于1024kb资源,打包成base64,
outDir:"build",
assetsDir:"static",
minify:false
},
})
vite
对于多入口打包,会自动进行依赖检测,如果有第三方包的时候,会自动打包进一个文件,与业务代码分离开,这是vite
自己做的优化,比较不错。
在dev-25b8fa7e.js
中,我们会看到import { $, l as lodashExports } from "./lodash-0339e1c5.js";
这一行代码,同时在index-16444b52.js
中,我出现了相同的代码。
gzip压缩策略
- 描述:通常是服务端对资源进行压缩,浏览器端对资源进行解压。
- 背景:通常情况下,一个文件顶多十几kb、几十kb,如果资源真的过大,那就是相当严重的情况了,上面我们讲解了分包策略,这里我们使用gzip压缩。
- 实践:
vite
提供了vite-plugin-compression
来进行gzip
压缩。
import viteCompression from 'vite-plugin-compression';
export default defineConfig ({
...
plugins: [viteCompression()],
})
这个插件就是开箱即用的,但是我们需要去告知后端设置解压缩方式为:"Content-Encoding":"gzip"
。但是物极必反,不是很大的文件,就不需要去开启gizp
压缩,因为浏览器解压缩,也需要时间。
动态导入策略(Dynamic import)
vite
的动态导入不像webpack
一样,因为webpack
在初期会遍历所有依赖形成依赖图,再去启动一个devServer
,所以他的动态导入只是针对于编译阶段(或许这样说的不妥),但是vite
相比于webpack
来讲,确实没有前期这样的一个构建过程,而是先启动一个开发服务器,在请求到入口文件
的时候,根据入口文件里面的内容,可能再会去请求其余的依赖
,这种按需加载
称之为动态导入
。动态导入的示例可以参照 >>>重学webpack系列(九) -- webpack的高级特性与前端性能优化
cdn加速策略
- 背景:因为客户在使用我们的应用的场景可能在全球各地,你的服务器只是在某一地,这样客户客户端请求资源的时候,就必须先到达你的服务器,如果距离过长,那么
http
请求链路耗时就会过长,cdn
策略表示,多台服务器具有资源,你请求距离你距离最近的一台资源就可以了。 - 实践:
vite
给我们提供了一个插件vite-plugin-cdn-import
。
// vite.config.js
import reactRefresh from '@vitejs/plugin-react-refresh'
import importToCDN from 'vite-plugin-cdn-import'
export default {
plugins: [
importToCDN({
modules: [
{
name: 'react', // cnd导出名字,
var: 'React', // cdn导出全局变量,比如jQuery:$,lodash:_
path: `umd/react.production.min.js`, // cdn地址,用script引入页面
},
{
name: 'react-dom',
var: 'ReactDOM',
path: `umd/react-dom.production.min.js`,
},
],
}),
],
}
是不是经过上述这么一整,加载资源的速度又快了很多?
总结
关于vite
里面的代码压缩等一些功能,vite
已经帮我做了,这里我们就不去深究了,下一章 >>> 前端构建工具vite进阶系列(七) -- vite与ts、框架的结合实践