1. webpack 开发和生产优化
资料参考1:https://www.cnblogs.com/wangjiachen666/p/11561186.html#_label1
资料参考2:https://blog.csdn.net/weixin_39699163/article/details/111649313
优化方向: 提升构建速度、减少构建后文件体积
2. 作用域提升(Scope Hoisting)
开发环境开启后,分析模块间的依赖关系,尽可能将被打散的模块合并到一个函数中,但不能造成代码冗余,所以只有被引用一次的模块才能被合并。
此功能开启会增加构建时间和时热模块替换功能失效,所以不可在开发环境开启
optimization: {
concatenateModules: true, // webpack4.0 在生产环境下默认时true
},
3. hash 缓存
1、hash:项目每次构建都会生成一个新hash,每个使用hash的文件内容改变,都会重构项目
2、chunkhash:根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,
生成对应的哈希值,每个出口的hash时不同的,也就不会相互影响。在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。并且webpack4中支持了异步import功能,顾chunkhash也作用于此。这样就会有个问题,只要对应css或则js改变,与其关联的文件hash值也会改变,但其内容并没有改变呢,所以没有达到缓存意义。顾contenthash的用途随之而来。
3、contenthash:是针对文件内容级别的,只有你自己模块的内容变了,那么hash值才改变,所以我们可以通过contenthash解决上诉问题。
所以:多出口的 output 设置 chunkhash,单入口也是chunkhash,
在通过import引入到main.js的文件,如css文件,设置contenthash
// 打包出口设置 chunkhash
output: {
filename: "[name]-[chunkhash:20].js",
},
// css 提取成独立文件设置 contenthash
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name]-[contenthash:10].css",
}),
},
4. webpack使用外部 cdn 资源
cdn官网: https://www.bootcdn.cn/
像jquery、vue、vue-router等依赖包、在构建项目的时候会很耗费时间、特别是如果写入构建后的主文件,体积超大,(使用cdn,可减少构建时间和减少打包后的项目体积)
- 安装依赖包
cnpm i vue vue-router jquery -S - 在main.js中使用
import Vue from 'vue'
import VueRouter from 'vue-router'
import $ from 'jquery'
- 在webpack.config.js中 配置 externals
在 externals 检测到,构建时就不构建node_modules中对应的包
externals: {
'vue': 'Vue',
'vue-router': 'VueRouter',
'jquery': '$'
},
- 在 index.html 中引入cdn
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
</body>
</html>
5. 配置静态资源路径(前缀拼接)
- 打包后在html中,为静态资源补上 url 前缀
- 不会上传到服务器,但是一定要上传到服务器指定位置,
output: {
publicPath: "https://cdn.bootcss.com/assets/",
},
6. css 压缩
将打包后的 css 文件进行压缩,减小体积从而减小带宽消耗,提升用户体验
- 安装依赖
cnpm i optimize-css-assets-webpack-plugin -D - 在 webpack 配置文件中配置
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
plugins: [
new OptimizeCSSAssetsPlugin({
cssProcessor: require("cssnano"), //引入cssnano引擎,来自 postcss-loader
cssProcessorOptions: {
discardComments: { removeAll: true },
},
}),
]
6. html 压缩
将打包后的 html文件进行压缩,减小体积从而减小带宽消耗,提升用户体验
- 安装依赖
cnpm i html-webpack-plugin -D - 在 webpack 配置文件中配置
plugins: [
new HtmlWebpackPlugin({
//选择html模板
title: "首页",
template: "./src/index.html",
filename: "index.html",
minify: {
// 压缩HTML文件
removeComments: true, // 移除HTML中的注释
collapseWhitespace: true, // 删除空白符与换行符
minifyCSS: true, // 压缩内联css
},
}),
],
7. css tree-shaking(摇树)
摇掉引入后但未使用,或者定义后没有使用的代码
1. css 摇树
- 安装依赖:cnpm i glob-all purify-css purifycss-webpack -D
- 在webpack配置文件中使用
const PurifyCSS = require("purifycss-webpack");
plugins: [
// 对匹配到的文件下的css进行摇树处理
new PurifyCSS({
paths: glob.sync([
path.resolve(__dirname, "./src/*.html"),
path.resolve(__dirname, "./src/*.js"),
]),
}),
],
2. js 摇树
- 说明:webpack 本身支持 js 摇树,所以配置 optimization.usedExports: true,
开发环境不生效,只有生产环境才生效(mode:'production'),但是开发环境有注释标注哪个被使用啦 - 注意: 只是支持 import 引入的文件摇树,不支持 commonjs 的 require 引入,针对依赖包和自定义的 js 文件
安装依赖:cnpm i uglify-js -D (不需要配置,不安装会报错) - 在webpack的配置文件中
optimization: {
usedExports: true,
},
回避摇树
被指定的文件将不被摇树处理
- 在 package.json 中新增 slideEffects 属性,这个属性接收 false 或者数组,数组中放 global-all 修饰的类型文件,或者指定路径
"sideEffects": [
"*.less"
],
8. 代码分割,code splitting
- 使用 vue 这种 spa 单页应用有很多好处,但是由于后见后全部打包进入 main.js,就造成了体积过大不利于下载,无法充分利用浏览器资源,所以 我们将体积大的公共的模块分割出去,单独生产 js 文件
- 参数:如果全部满足,则会被分割,其中注意 cacheGroups (可以将多个模块打包成一个文件,支持命名)
optimization: {
splitChunks: {
chunks: "all", // 支持异步和同步
minChunks: 2, // 最少被引入次数
automaticNameDelimiter: "-", // 分割后的连接符
cacheGroups: {
// odash 打包成一个独立的文件
lodash: {
test: /lodash/,
name: "lodash",
},
// react和react-dom一起打包成一个独立的文件
react: {
test: /react|react-dom/,
name: "react",
},
},
},
},
9. prefetch 预取 和 preload 预加载 (使用魔法注释的方式)
- prefetch 预取 (页面初始不加载,等所有进程执行完空闲下来后加载,使用场景像下拉列表数据,即初始不需要展示的数据)
- preload 预加载 (一个效果,并行执行,不等进程空闲)
// 场景 1:初始化预取,不需要马上执行的模块
import(/_webpackChunkName:'test',webpackPrefetch:true_/'./test')
/// 场景 2:等这个模块加载完执行,里面方法
async function(){
const result = await import(/_webpackChunkName:'test',webpackPrefetch:true_/'./test')
}
10. 构建动态链接库
- DllPlugin 插件打包第三⽅类库,生成动态链接库, 优化构建性能
- .dll ⽂件称为动态链接库,用来做缓存的,在 windows 系统会经常看到,
- 就是先运行打包构建会生成第三方包的对应的.dll 文件,然后再次实际打包的时候会检测,将有.dll 文件的第三方包不列入打包构建范围,那么就减少了构建的时间,且不影响生产环境
- webpack 已经内置了对动态链接库的⽀持
DllPlugin:⽤于打包出⼀个个单独的动态链接库⽂件
DllReferencePlugin:⽤于在主要的配置⽂件中引⼊ DllPlugin 插件打包好的动态链接库⽂件
- 单独创建一个 webpack 配置文件,webpack.config.dll.js 用于执行生产 dll 文件的指令,在 package 中执行 build:dll,生成 json 文件(做路径映射用的,js 文件是主文件)
//构建动态链接库的配置文件
const path = require("path");
const { DllPlugin } = require("webpack");
module.exports = {
mode: "production",
entry: {
react: ["react", "react-dom"],
},
output: {
path: path.resolve(__dirname, "./dist/dll/"),
filename: "[name].dll.js",
library: "reactLib",
},
plugins: [
new DllPlugin({
// 配置生成的dll json文件的路径
path: path.join(__dirname, "./dist/dll/", "[name]-manifest.json"),
// 对外暴露的函数名
name: "react",
}),
],
};
- 在package.json中
"build:dll": "webpack --config ./webpack.config.dll.js"
- 然后在webpack.config.js配置文件中,使用 DllReferencePlugin 用于构建时指定这个 dll 映射
const webpack = require("webpack");
plugins: [
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, "./dll/react-manifest.json"),
}),
]