总结整理前端工作中涉及到的优化方案
一、懒加载
1.懒加载的概念
懒加载也称为延迟加载、按需加载,指的是在一个网页中延迟加载大量的图片数据,是一种比较好的网页性能优化方式。当我们一个页面中用到了大量的图片,如果在首次加载的时候一次性全部加载,在网络情况不佳时,造成图片加载缓慢或者加载失败,是否造成不良好的用户体验。
使用图片懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,随着滚动屏幕到可视区域,图片才会加载。这样使得网页的加载速度快了,服务器的负载也减轻了。
2.懒加载的特点
- 减少无效资源加载: 使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
- 提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而懒加载就可以大大提升用户体验。
- 防止加载过多图片而影响其他资源文件的加载: 会影响网站的正常使用。
3.懒加载的实现原理
图片的加载是由src属性引发的,当对src属性赋值时,浏览器就会发送一个http请求图片资源。根据这个原理,我们可以使用HTML5的data-xxx属性来存储图片的路径,在需要加载图片的时候,将data-xxx中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx中的xxx可以自定义,这里我们用data-src来定义
懒加载的实现重点在于确定用户需要加载哪些图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。
下面使用两种方式来实现懒加载:
1. 使用原生JavaScript实现懒加载:
[ 知识点: ]
(1) window.innerHeight是浏览器可视区的高度。
(2) document.body.scrollTop || document.documentElement.scrollTop 是浏览器滚动过的距离
(3) imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离)
[ 图示: ]
[ code: ]
<div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>
<script setup>
const imgs = document.querySelectorAll('img');
function lozyLoad(){
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
const winHeight= window.innerHeight;
for(let i=0;i < imgs.length;i++){
if(imgs[i].offsetTop < scrollTop + winHeight ){
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}
window.onscroll = lozyLoad;
</script>
2. 使用IntersectionObserver属性实现:
[ 触发条件: ]
- 每当目标元素与设备视图或者其他元素发生交集的时候执行。设备视窗或者其他元素我们称它为根元素或根(root)。
- Observer第一次监听目标元素的时候。 [ 使用条件: ]
- 图片懒加载——当图片滚动到可见时才进行加载。
- 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而不需用户操作翻页,给用户一种网页可以无限滚动的错觉。
- 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况。
- 在用户看见某个区域时执行任务或播放动画。
[ code: ]
<div class="container">
<img style="height:1080px;" data-src="./png1.png" />
<img style="height:1080px;" data-src="./png2.png" />
<img style="height:1080px;" data-src="./png3.png" />
<img style="height:1080px;" data-src="./png4.png" />
<img style="height:1080px;" data-src="./png5.png" />
<img style="height:1080px;" data-src="./png6.png" />
</div>
<script>
const imgs = document.querySelectorAll("img");
const observe = new IntersectionObserver((observes) => {
observes.forEach((ele) => {
//如果isIntersecting为true,则说明元素进入可视化区域
if (ele.isIntersecting) {
//do something...
ele.target.src = ele.target.dataset.src;
observe.unobserve(ele.target); //取消监听
}
});
});
//创建observe后需要给定一个目标元素进行观察:
imgs.forEach((el) => {
observe.observe(el);
});
</script>
4.懒加载与预加载的区别
两种方式都是提高页面性能的方式,两者主要区别是:一个为提前加载,一个为迟缓加载甚至不加载。懒加载对服务器有一定的缓解压力作用,预加载则会增加服务器压力。
- 懒加载: 当用户需要访问时,再去加载,这样可以提高网站的首屏加载速度,提升用户体验,并且可以减少服务器的压力。它适用于图片很多,页面很长的网站。
- 预加载: 将所需的资源提前请求加载到本地,这样在后面需要用到时可以直接从缓存中获取。通过预加载能够减少用户的等待时间,提高用户体验。它适用于需要加载比较大的视频或图片场景。
二、回流与重绘
1.回流与重绘的概念及触发条件
(1)回流
当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程就称为回流。
下面这些操作都会导致回流:
- 页面的首次渲染
- 浏览器的窗口大小发生变化
- 元素的内容发生变化
- 元素的尺寸或者位置发生变化
- 元素的字体大小发生变化
- 激活CSS伪类
- 查询某些属性或者调用某些方法
- 添加或者删除可见的DOM元素 在触发回流(重排)的时候,由于浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致周围的DOM元素重新排列,它的影响范围有两种:
- 全局范围:从根节点开始,对整个渲染树进行重新布局
- 局部范围:对渲染树的某部分或者一个渲染对象节点进行重新布局
(2)重绘
当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,这个过程就是重绘。 下面这些操作会导致重绘:
- color、background相关属性:background-color、background-image等
- outline相关属性:outline-color、outline-width、text-decoration
- border-radius、visivility、box-shadow 注意:当触发回流时,一定会触发重绘,但是重绘不一定会引发回流。
2.如何避免回流与重绘?
减少回流与重绘的措施:
- 操作DOM时,尽量在低层级的DOM节点进行操作
- 不要使用table布局,一个小的改动可能会使整个table进行重新布局
- 不要使用CSS的表达式
- 不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式
- 使用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素
- 避免频繁操作DOM,可以创建一个文档片段documentFragment,在它上面应用所有DOM操作,最后一次性添加到文档中
- 将元素先设置display:none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘
- 将DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制 浏览器针对页面的回流与重绘,进行了自身的优化————渲染队列
浏览器会将所有的回流、重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流、重绘变成一次回流重绘。
上面,将多个读操作(或者写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,本应该多次触发回流,变成了只触发一次回流。
3.如何优化动画?
对于如何优化动画,我们知道,一般情况下,动画需要频繁的操作DOM,就会导致页面性能问题,我们可以将动画的position属性设置为absolute或者fixed,将动画脱离文档流,这样他的回流就不会影响到页面。
4.documentFragment是什么?用它跟直接操作DOM的区别是什么?
MDN中对documentFragment的解释:
DocumentFragment,文档片段接口,一个没有父对象的最小文档对象。它被作为一个轻量版的Document使用,就像标准的document一样,存储由节点(nodes)组成的文档结构。与document相比,最大的区别是DocumentFragment不是真实DOM树的一部分,它的变化不会触发DOM树的重新渲染,且不会导致性能等问题。
当我们把一个DocumentFragment节点插入文档树时,插入的不是DocumentFragment自身,而是它的所有子孙节点。在频繁的DOM操作时就,我们可以将DOM元素插入DocumentFragment,之后一次性的将所有的子孙节点插入文档中。和直接操作DOM相比,将DocumentFragment节点插入DOM树时,不会触发页面的重绘,这样就大大提高了页面的性能。
三、节流与防抖
1.对节流防抖的理解
- 防抖:在持续触发函数时,间隔一定时间未触发才会触发一次。
- 节流:在持续触发函数时,间隔一定时间触发一次。
防抖函数的应用场景:
- 按钮提交场景:防止多次提交,只执行最后一次。
- 输入查询场景:防止连续输入请求,只执行连续输入的最后一次。
节流函数使用场景:
- 拖拽场景:固定时间只执行一次,防止超高频次触发位置变动。
- 滚动场景:监控浏览器resize。
- 动画场景:避免短时间内多次触发动画引起性能问题。
2.实现节流函数和防抖函数
防抖:
function debounce(fn, wait) {
var timer = null;
return function() {
var context = this,
args = [...arguments];
// 如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
节流:
// 时间戳版
function throttle(fn, delay) {
var preTime = Date.now();
return function() {
var context = this,
args = [...arguments],
nowTime = Date.now();
// 如果两次时间间隔超过了指定时间,则执行函数。
if (nowTime - preTime >= delay) {
preTime = Date.now();
return fn.apply(context, args);
}
};
}
// 定时器版
function throttle (fun, wait){
let timeout = null
return function(){
let context = this
let args = [...arguments]
if(!timeout){
timeout = setTimeout(() => {
fun.apply(context, args)
timeout = null
}, wait)
}
}
}
四、图片优化
1.平时项目中常用的图片优化技巧
- 不用图片(hh,不用图片就不用优化啦)。很多时候用到的一些修饰类图片,能用CSS解决就不用图片!!!
- 对于移动端来说,屏幕宽度小,完全没有必要请求原图浪费宽带。图片都用CDN(CDN是将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高用户访问的响应速度和成功率。解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。)加载,可以计算出适配屏幕的宽度,然后去请求相应裁好的图片。
- 小图使用base64格式。
- 多个图标文件可以合并为雪碧图。
- 选择正确的图片格式。
- 对于能够显示WebP格式的浏览器尽量使用WebP格式。因为WebP格式具有极好的图像数据压缩算法,能带来更小的图片体积以及肉眼无差识别的质量,缺点就是兼容性。
- 小图使用PNG,其实对于大部分图标这种图片,完全可以使用svg代替。
- 照片使用JPEG。
2.常见图片格式及使用场景
索引色:为节约存储,把图像中使用的颜色与一个颜色表对应起来,索引色常使用16色、32色、64色、128色或256色等,但最多不得超过256色。
直接色:每个像素值分成R,G,B分量,每个分量作为单独的索引值对它做变换。也就是通过相应的彩色变换表找出基色强度,用变换后得到的R,G,B强度值产生的彩色称为直接色。它的特点是对每个基色进行变换。
- BMP:是无损的、既支持索引色也支持直接色的点阵图。这种图片格式几乎没有对数据进行压缩,所以BMP格式相对比较大。
- GIF:是无损的、采用索引色的点阵图。采用LZW压缩算法进行编码。文件小,是GIF格式的优点,同时,GIF格式还具有支持动画以及透明的优点。但是GIF格式仅支持8bit的索引色,所以GIF格式适用于对色彩要求不高同时需要文件体积较小的场景。
- JPEG:是有损的、采用直接色的点阵图。JPEG的图片的优点是采用了直接色,得益于更丰富的色彩,JPEG非常适合用来存储图片,与GIF相比,JPEG不适合用来存储企业Logo、线框类的图。因为有损压缩会导致图片模糊,而直接色的选用,又会导致图片文件比GIF更大。
- PNG-8:是无损的、使用索引色的点阵图。PNG是一种比较新的图片格式,PNG-8是非常好的GIF格式替代者,在可能的情况下,应该尽可能的使用PNG-8而不是GIF,因为在相同的图片效果下,PNG-8具有更小的文件体积。除此之外,PNG-8还支持透明度的调节,而GIF并不支持。除非需要动画的支持,否则没有理由使用GIF而不是PNG-8。
- PNG-24:是无损的、使用直接色的点阵图。PNG-24的优点在于它压缩了图片的数据,使得同样效果的图片,PNG-24格式的文件大小要比BMP小得多。当然,PNG-24的图片还是要比JPEG、GIF、PNG-8。
- SVG:是无损的矢量图。SVG是矢量图意味着SVG图片由直线和曲线以及绘制它们的方法组成。当放大SVG图片时,看到的还是线和曲线,而不会出现像素点。这意味着SVG图片在放大时,不会失真,所以它适合用来绘制Logo、Icon等。
- WebP:是谷歌开发的一种新图片格式,WebP是同时支持有损和无损压缩的、使用直接色的点阵图。从名字就可以看出来它是为Web而生的,何出此言呢?就是说相同质量的图片,WebP格式具有更小的文件体积。现在网站上充满大量的图片,如果能够降低每一个图片的文件大小,那么将大大减少浏览器和服务器之间的数据传输量,进而降低访问延迟,提升访问体验。目前只有Chrome和Opera浏览器支持WebP格式,兼容性不太好。
- 在无损压缩的情况下,相同质量的WebP图片,文件比PNG小26%。
- 在有损压缩的情况下,具有相同图片精度的WebP图片,文件要比JPEG小25% - 34%。
- WebP图片格式支持图片透明度,一个无损压缩的WebP图片,如果要支持透明度只需要22%的额外文件大小。
五、Webpack优化
1.如何提高Webpack的打包速度
(1) 优化Loader
对于Loader来说,影响打包效率首当其中必属Babel了。因为Babel会将代码转为字符串生成AST,然后对AST进行转变最后生成新的代码,项目越大,转换代码越多,效率越低。当然,这是可以优化的。
首先我们优化Loader的文件搜索范围
module.exports = {
module: {
rules: [
{
// js 文件才使用 babel
test: /\.js$/,
loader: 'babel-loader',
// 只在 src 文件夹下查找
include: [resolve('src')],
// 不会去查找的路径
exclude: /node_modules/
}
]
}
}
对于Babel来说,希望只作用在JS代码上的,然后node_modules中使用的代码都是编译过的,所以完全没有必要再去处理一遍。
当然这样做还不够,还可以将Babel编译过的文件缓存起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间。
loader: 'babel-loader?cacheDirectory=true'
(2) HappyPack
受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。
HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
module: {
loaders: [
{
test: /\.js$/,
include: [resolve('src')],
exclude: /node_modules/,
// id 后面的内容对应下面
loader: 'happypack/loader?id=happybabel'
}
]
},
plugins: [
new HappyPack({
id: 'happybabel',
loaders: ['babel-loader?cacheDirectory'],
// 开启 4 个线程
threads: 4
})
]
(3)DllPlugin
DllPlugin 可以将特定的类库提前打包然后引入。这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。DllPlugin的使用方法如下:
// 单独配置在一个文件中
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: {
// 想统一打包的类库
vendor: ['vue']
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].dll.js',
library: '[name]-[hash]'
},
plugins: [
new webpack.DllPlugin({
// name 必须和 output.library 一致
name: '[name]-[hash]',
// 该属性需要与 DllReferencePlugin 中一致
context: __dirname,
path: path.join(__dirname, 'dist', '[name]-manifest.json')
})
]
}
然后需要执行这个配置文件生成依赖文件,接下来需要使用 DllReferencePlugin
将依赖文件引入项目中
// webpack.conf.js
module.exports = {
// ...省略其他配置
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
// manifest 就是之前打包出来的 json 文件
manifest: require('./dist/vendor-manifest.json'),
})
]
}
(4)代码压缩
在 Webpack3 中,一般使用 UglifyJS
来压缩代码,但是这个是单线程运行的,为了加快效率,可以使用 webpack-parallel-uglify-plugin
来并行运行 UglifyJS
,从而提高效率。
在 Webpack4 中,不需要以上这些操作了,只需要将 mode
设置为 production
就可以默认开启以上功能。代码压缩也是我们必做的性能优化方案,当然我们不止可以压缩 JS 代码,还可以压缩 HTML、CSS 代码,并且在压缩 JS 代码的过程中,我们还可以通过配置实现比如删除 console.log
这类代码的功能。
(5)其他
可以通过一些小的优化点来加快打包速度
resolve.extensions
:用来表明文件后缀列表,默认查找顺序是['.js', '.json']
,如果你的导入文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面resolve.alias
:可以通过别名的方式来映射一个路径,能让 Webpack 更快找到路径module.noParse
:如果你确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助
2.如何用webpack来优化前端性能
⽤webpack优化前端性能是指优化webpack的输出结果,让打包的最终结果在浏览器运⾏快速⾼效。
- 压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的 UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件, 利⽤ cssnano (css-loader?minimize)来压缩css
- 利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于 output 参数和各loader的 publicPath 参数来修改资源路径
- Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动webpack时追加参数 --optimize-minimize 来实现
- Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
六、vue3项目打包优化配置
在vue3的项目中,原本配置webpack目录结构不见了,取而代之的则是vue.config.js(在根目录自建!)。
1.打包后不需要生成sourcemap文件
module.exports={
productionSourceMap:false
}
2.图片压缩
vue正常打包之后一些图片文件很大,使打包体积很大,通过image-webpack-loader插件将大的图片进行压缩从而减小打包体积
(1) 先安装依赖:npm i image-webpack-loader --save-dev (2) 在vue.config.js中写入
module.exports={
productionSourceMap:false,
chainWebpack:config=>{
//=========压缩图片 start========
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({bypassOnDebug:true})
.end()
//=========压缩图片 end========
}
}
3.cdn配置(可选)
(1) 在vue.config.js最上边写入
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development'
// 本地环境是否需要使用cdn
const devNeedCdn = false
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
// cdn的css链接
css: [],
// cdn的js链接
js: [
'https://unpkg.com/vue@next',
'https://cdn.staticfile.org/vuex/3.1.0/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
(2) 在vue.config.js
module.exports
chainWebpack
中写入:
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
// ============注入cdn start============
(3) 在vue.config.js
module.exports
configureWebpack
中写入:
configureWebpack: config => {
// 用cdn方式引入,则构建时要忽略相关资源
if (isProduction || devNeedCdn) config.externals = cdn.externals
}
(4) 当前配置的vue.config.js
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development'
// 本地环境是否需要使用cdn
const devNeedCdn = false
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
// cdn的css链接
css: [],
// cdn的js链接
js: [
'https://unpkg.com/vue@next',
'https://cdn.staticfile.org/vuex/3.1.0/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
module.exports = {
productionSourceMap: false,
chainWebpack: config => {
// ============压缩图片 start============
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
// ============压缩图片 end============
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
// ============注入cdn start============
},
configureWebpack: config => {
// 用cdn方式引入,则构建时要忽略相关资源
if (isProduction || devNeedCdn) config.externals = cdn.externals
}
}
(5) 在public
index.html
写入
<!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,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<!-- 使用CDN的CSS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.css) { %>
<link
href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
rel="stylesheet"
/>
<% } %>
<!-- 使用CDN的CSS文件 -->
<title>cdn引入</title>
</head>
<body>
<noscript>
<strong
>We're sorry but cli3_base doesn't work properly without
JavaScript enabled. Please enable it to continue.</strong
>
</noscript>
<div id="app"></div>
<!-- 使用CDN的JS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdn &&
htmlWebpackPlugin.options.cdn.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>
<!-- 使用CDN的JS文件 -->
<!-- built files will be auto injected -->
</body>
</html>
(6) 重启项目npm run serve
(7) 在src/router.js
修改
将
Vue.use(Router)
改为
if (!window.VueRouter) Vue.use(Router)
(8) 重新启动npm run serve
即可,现在的配置是开发环境,在浏览器的Network JS
里面是看不到的。若想查看,请将vue.config.js
里面的
// 本地环境是否需要使用cdn
const devNeedCdn = false
改为
// 本地环境是否需要使用cdn
const devNeedCdn = true
七、代码压缩
(1) 安装依赖:npm i -D uglifyjs-webpack-plugin (2) 在vue.config.js 头部引入文件
//代码压缩
const UglifyJsPlugin=require('uglifyjs-webpack-plugin');
(3) 在vue.config.js
module.exports
configureWebpack
里面新增
// 生产环境相关配置
if (isProduction) {
// 代码压缩
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
//生产环境自动删除console
compress: {
// warnings: false, // 若打包错误,则注释这行
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
}
八、开启Gzip
(1) 安装依赖:npm i --save-dev compression-webpack-plugin@5.0.1
(2) 在vue.config.js
顶部引入依赖
//gzip压缩
const CompressionWebpackPlugin=require('compression-webpack-plugin')
(3) 在vue.config.js
module.exports
configureWebpack
里面新增,直接放在代码压缩下边即可
// 生产环境相关配置
if (isProduction) {
// 代码压缩
// ..................
// gzip压缩
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
}
九、公共代码抽离
(1) 在vue.config.js
module.exports
configureWebpack
里面新增,直接放在gzip压缩下边即可
// 公共代码抽离
config.optimization = {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,
maxInitialRequests: 5,
minSize: 0,
priority: 100
},
common: {
chunks: 'all',
test: /[\/]src[\/]js[\/]/,
name: 'common',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 60
},
styles: {
name: 'styles',
test: /.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true
},
runtimeChunk: {
name: 'manifest'
}
}
}
}
最后,奉上完成的vue.config.js
// 代码压缩
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
// gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// 是否为生产环境
const isProduction = process.env.NODE_ENV !== 'development'
// 本地环境是否需要使用cdn
const devNeedCdn = true
// cdn链接
const cdn = {
// cdn:模块名称和模块作用域命名(对应window里面挂载的变量名称)
externals: {
vue: 'Vue',
vuex: 'Vuex',
'vue-router': 'VueRouter'
},
// cdn的css链接
css: [],
// cdn的js链接
js: [
'https://unpkg.com/vue@next',
'https://cdn.staticfile.org/vuex/3.1.0/vuex.min.js',
'https://cdn.staticfile.org/vue-router/3.0.3/vue-router.min.js'
]
}
module.exports = {
productionSourceMap: false,
chainWebpack: config => {
// ============压缩图片 start============
config.module
.rule('images')
.use('image-webpack-loader')
.loader('image-webpack-loader')
.options({ bypassOnDebug: true })
.end()
// ============压缩图片 end============
// ============注入cdn start============
config.plugin('html').tap(args => {
// 生产环境或本地需要cdn时,才注入cdn
if (isProduction || devNeedCdn) args[0].cdn = cdn
return args
})
// ============注入cdn start============
},
configureWebpack: config => {
// 用cdn方式引入,则构建时要忽略相关资源
if (isProduction || devNeedCdn) config.externals = cdn.externals
// 生产环境相关配置
if (isProduction) {
// 代码压缩
config.plugins.push(
new UglifyJsPlugin({
uglifyOptions: {
//生产环境自动删除console
compress: {
warnings: false, // 若打包错误,则注释这行
drop_debugger: true,
drop_console: true,
pure_funcs: ['console.log']
}
},
sourceMap: false,
parallel: true
})
)
// gzip压缩
const productionGzipExtensions = ['html', 'js', 'css']
config.plugins.push(
new CompressionWebpackPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: new RegExp(
'\.(' + productionGzipExtensions.join('|') + ')$'
),
threshold: 10240, // 只有大小大于该值的资源会被处理 10240
minRatio: 0.8, // 只有压缩率小于这个值的资源才会被处理
deleteOriginalAssets: false // 删除原文件
})
)
// 公共代码抽离
config.optimization = {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'all',
test: /node_modules/,
name: 'vendor',
minChunks: 1,
maxInitialRequests: 5,
minSize: 0,
priority: 100
},
common: {
chunks: 'all',
test: /[\/]src[\/]js[\/]/,
name: 'common',
minChunks: 2,
maxInitialRequests: 5,
minSize: 0,
priority: 60
},
styles: {
name: 'styles',
test: /.(sa|sc|c)ss$/,
chunks: 'all',
enforce: true
},
runtimeChunk: {
name: 'manifest'
}
}
}
}
}
}
}
使用gzip压缩需要配置nginx
server{
listen 8080
server_name localhost
gzip on;
gzip_min_length 1k;
gzip_comp_level 9;
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;
gzip_vary on;
gzip_disable "MSIE [1-6]\.";
location /appShare {
client_max_body_size 10m;
root /home/test/webIndex/appShare;
try_filtes $uri $uri/ /yourProduct/index.html;
index index.htm index.html;
}
}