不说废话
举个例子,比如一个js文件,你项目开启的时候,等你发出某个指令的时候,那个文件js才加载
但是有一个问题,当你发出指令时候,首先要下载这个js文件,然后浏览器再解析这个文件,如果这个文件很大的话,肯定会有一定的延迟,页面才有效果
OK,先说Prefetch,通俗的来讲就是当你打开项目的时候,这个文件不会加载,等你的浏览器有空闲的时候,它自动帮你把这个文件下载下来,这样当你需要这个文件的时候,你就可以省去第一步下载这个js文件的时间了,就提升了性能
举个例子,点击button的时候,加载我们的element.js文件
具体代码实现
/**/里面的是魔法注释,并不是真正的注释
const button = document.createElement("button");
button.innerHTML = "加载元素";
button.addEventListener("click", () => {
import(
/* webpackChunkName: 'element' */
/* webpackPrefetch: true */
"./element"
).then(({default: element}) => {
document.body.appendChild(element);
})
});
document.body.appendChild(button);
效果如下:
再说Preload,它其实跟Prefetch的作用差不多,区别就是它是跟我们的父脚本一起下载的,也就是包含它的js文件加载的时候,它就跟着一起加载了,不过我们在浏览器的调试中,看不到它的变化,不过它确实是起效果了
具体代码实现
const button = document.createElement("button");
button.innerHTML = "加载元素";
button.addEventListener("click", () => {
import(
/* webpackChunkName: 'element' */
/* webpackPreload: true */
"./element"
).then(({default: element}) => {
document.body.appendChild(element);
})
});
document.body.appendChild(button);
下面总结一下它们两个的不同之处
1.preload chunk 会在父 chunk 加载时,以并行方式开始加载。prefetch chunk 会在父 chunk 加载结束后开始加载。
2.preload chunk 具有中等优先级,并立即下载。prefetch chunk 在浏览器闲置时下载。
3.preload chunk 会在父 chunk 中立即请求,用于当下时刻。prefetch chunk 会用于未来的某个时刻。
4.浏览器支持程度不同。
二.CDN
缺点是,CDN服务器需要花钱买,不过也有免费的
好处是,当你使用CDN引入一些库和插件的时候,它不会被打包到你的项目当中,优化了性能
举个例子,我们使用lodash这个插件
index.html中
然后去我们的webpack配置里面
externals: {
lodash: "lodash",
},
然后在项目中就可以使用了,打包时候不会打包这个文件
如果你在本地觉得这样影响调试的话,你可以通过ejs来判断一下环境
<% if (process.env.NODE_ENV === 'production') { %>
<% } %>
开发环境直接用npm的,生产环境再用cdn的
三.Tree Shaking
这个东西的作用就是,当你项目在打包的时候,它会帮你剔除一些无用的js代码,从而降低包的体积,提升性能
usedExports需要结合Terser来一起实现
usedExports: 目的是标注出来哪些函数是没有被使用 unused
terser:将未使用的函数, 从我们的代码中删除
具体代码如下:
optimization: {
usedExports: true, // production
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
extractComments: false,
terserOptions: {
compress: {
arguments: false,
dead_code: true
},
mangle: true,
toplevel: true,
keep_classnames: true,
keep_fnames: true
}
})
]
},
再说sideEffects
sideEffects的作用就是用于告知webpack compiler哪些模块是有副作用的
举个例子
比如你import了一个js文件,但是实际上你并没有用到这个js文件,但是你打包的时候还是会打包
那么如何解决呢?
直接到我们的package.json里面,加一个sideEffects等于false即可
但是还有一个问题,比如你有的js文件想打包的时候给它剔除,有的js文件,你里面有全局变量,不想给它剔除,那咋办呢??
这样写,把你不想剔除的js文件,写入到里面去
这样,打包的时候,你的a.js文件就不会被剔除,而你没有写入这个数组的js文件就会被剔除
但是一些引入的css文件也会被剔除,咋办呢?
个人建议,最好写一些纯模块,这样直接把sideEffects设置为 false比较好
但是sideEffects设置为 false了,引入的css文件也会被剔除,咋办呢,好解决,去我们的webpack配置
总结一下:在我们真实的项目当中如何设置tree shaking
在react脚手架里面css有对sideEffects进行配置,vue里面好像没有,可能需要配置一下
四.purgeCSS
上面那个tree shaking是针对于我们的js代码,如何要对我们的css代码进行tree shaking的话,就要用到这个purgeCSS库
首先就是安装了
npm i purgecss-webpack-plugin -D
首先我们封装一个查找路径的方法
const path = require('path');
// node中的api
const appDir = process.cwd();
const resolveApp = (relativePath) => path.resolve(appDir, relativePath);
module.exports = resolveApp;
然后去配置我们的webpack
const glob = require('glob');
const resolveApp = require('./paths');
//假设我们所有的项目代码都在src目录下
plugins: [
paths: glob.sync(`${resolveApp("./src")}/**/*`, {nodir: true}),
})
]
如果你想让一些标签的样式不被删掉,这样写
new PurgeCssPlugin({
paths: glob.sync(`${resolveApp("./src")}/**/*`, {nodir: true}),
safelist: function() {
return {
standard: ["body", "html"]
}
}
})
body和html的样式,打包时候就不会被删掉
说明一下:如果你们使用less,scss写的css,tree shaking也会生效,它是对打包后的css进行tree shaking操作的
五.Gzip压缩
项目正常打包部署,直接在服务端对nginx配置进行修改。这样设置时,当你请求时,服务端就会先将对应的文件压缩成.gz格式再发送给你,客户端接收到了.gz文件的格式之后再解压并执行后续操作。相当于用压缩的时间,换取了文件传输的时间,通常都会是正优化,除非项目体积过小。
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
# 开启gzip
gzip on;
# 设置缓冲区大小
gzip_buffers 4 16k;
#压缩级别官网建议是6
gzip_comp_level 6;
#压缩的类型
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php;
server {
listen 8462;
server_name localhost;
location / {
root dist;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
项目打包时对webpack进行特殊设置,安装插件(compression-webpack-plugin);打包同时生成成两份文件,第一份为正常的文件,另一个为gz压缩后的文件,部署时将其全部部署至服务端。
const CompressionPlugin = require('compression-webpack-plugin');
module.exports= {
configureWebpack: {
plugins: [
new CompressionPlugin({
algorithm: 'gzip', // 使用gzip压缩
test: /\.js$|\.html$|\.css$/, // 匹配文件名
filename: '[path].gz[query]', // 压缩后的文件名(保持原文件名,后缀加.gz)
minRatio: 1, // 压缩率小于1才会压缩
threshold: 10240, // 对超过10k的数据压缩
deleteOriginalAssets: false, // 是否删除未压缩的源文件,谨慎设置,如果希望提供非gzip的资源,可不设置或者设置为false(比如删除打包后的gz后还可以加载到原始资源文件)
})
],
},
}
之后在nginx配置中使用:gzip_static on,该属性能够静态加载本地的gz文件,这样就完成了gzip。另外注意一下,如果我们的一个css或者js文件,里面的内容太少了,它是不会压缩这个文件的
六.InlineChunkHtmlPlugin
就相当于把我们的一些js代码,直接内嵌到html,当我们的html加载的时候,会一起把这些js文件加载,但是也会增加我们的html的体积
首先安装两个插件
npm i react-dev-utils -D
npm i html-webpack-plugin -D
然后配置我们的webpack
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//a表示我们要注入的js文件名,根据你的实际命名来
plugins: [
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/a.*\.js/,])
]
七.webpack-bundle-analyzer
这个插件可以看见你项目打包之后,哪些文件过大,然后你自己进行代码的优化
npm i webpack-bundle-analyzer -D
然后在scripts中
"analyzer": "use_analyzer=true npm run serve",
再去webpack
module.exports ={
chainWebpack: config => {
if (process.env.use_analyzer) {
config
.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}
},
}
之后运行
npm run analyzer