# webpack_opt **Repository Path**: pipepandafeng/webpack_opt ## Basic Information - **Project Name**: webpack_opt - **Description**: webpack 优化项 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-09-27 - **Last Updated**: 2022-06-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: webpack ## README # 🌴 webpack opt 本次基于webpack@5.54.0, 完成相关 webpack 优化,具体相关配置参数请查看官网 > 官网:https://webpack.docschina.org --- ## 安装 webpack 相关环境并完成配置 > 核心包: `webpack` , `webpack-cli` , `webpack-dev-server` , `html-webpack-plugin` , `@babel/core` , `@babel/preset-env` , `babel-loader` , `clean-webpack-plugin` --- ## noParse 加快构建速度 > 防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。 所以总的结论是: 文件中没有任何导入就可以使用 noParse 列子:引用 jquery 时,使用 noParse 加快打包速度 1 ```js module: { noParse: /jquery|lodash/, } ``` --- ## IgnorePlugin > 忽略第三方包中的一些不使用的文件,减少打包体积 moment.js 举例, 去除 webpack 中其他语言包,只导入之际所需要的语言包 * 未使用 momentjs 打包体积`660KB` * 使用 momentjs 打包体积 `2.14MB` * 使用 monmentjs, 配合 IgnorePlugin 插件 打包体积`1.01M` ```js /* webpack.config.js */ const webpack = require('webpack') module.exports = { ..., plugins: [ new webpack.IgnorePlugin({ resourceRegExp: /^\.\/locale$/, contextRegExp: /moment$/, }) ] } /* index.js中使用momentjs */ import * as moment from 'moment'; import 'moment/locale/zh-cn'; console.log(moment.locale('zh-cn')); console.log(moment(1316116057189).fromNow()); ``` --- ## dllPlugin 动态连接库 > 动态链接库好处:减小入口文件大小,比如减小 index.js 文件大小,避免首屏加载过慢。单独打包了第三方库文件,加快了打包编译速度。但动态链接库的使用不一定会整体减少构建包的体积。 分别以 react 和 vue 来举例 1. react 举例 * 安装 react 环境 > 三个核心包: `react` , `react-dom` , `@babel/preset-react` ```js /* 主要在babel presets添加对@babel/preset-react 解析react语法*/ /* .babelrc */ { "presets": [ [ "@babel/preset-env", { "targets": "defaults" } ], [ "@babel/preset-react", { "targets": { "node": "current" } } ] ] } ``` * 动态链接库基本配置 ```js 1: /* 新建打包第三方的webpack配置文件 */ /* webpack.config.react.js 生产json清单路径*/ module.exports = { plugins: [ new webpack.DllPlugin({ name: '_dll_[name]', path: path.resolve(__dirname, "dist", "manifest.json"), }) ] } 2: /* 主配置文件 */ /* webpack.config.js 该去那里查找清单路径*/ new webpack.DllReferencePlugin({ manifest: path.resolve(__dirname, "dist", "manifest.json"), }) /* CleanWebpackPlugin设置cleanOnceBeforeBuildPatterns属性,每次打包不会清空dll文件夹下文件,避免每次都打包第三方库 */ new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ["**/*", "!dll/**"], }), ``` ```html 3: /* index.html 引入打包后的第三方js */ ``` * react 打包文件对比(基于生产模式 production) | 构建包体积 | 入口文件大小 | 第三方打包文件大小 | | ---------- | :----------: | -----------------: | | 126kb | 125kb | / | | 129kb | 小于 1KB | 128kb | * vue 打包文件对比(基于生产模式 production, 采用 vue 运行时的版本) | 构建包体积 | 入口文件大小 | 第三方打包文件大小 | | ---------- | :----------: | -----------------: | | 64.1kb | 63.7kb | / | | 65.0kb | 小于 1KB | 64.1kb | --- ## happypack 多线程打包 > 开启多线程打包,加快打包构建速度。 ```js /* webpack.config.js */ module.exports = { rules: [ rules: [{ test: /\.m?js$/, exclude: /node_modules/, use: "happypack/loader", }] plugins: [ new HappyPack({ threads: 4, loaders: ["babel-loader"], }), ] } ``` --- ## webpack 中自带优化(仅限于生产模式 production) 1. tree-shaking > 把没用的代码自动删除 ```js /* unit.js */ const sum = (a, b) => { return a + b; }; const minus = (a, b) => { return a - b; }; export default { sum, minus, }; ``` ```js /* index.js */ import calc from "./utils.js"; console.log(calc.sum(1, 2)); ``` 打包后 webpack 会自动去掉 minus 函数,因为它没有被调用过 2. scope hosting 作用域提升 > 在 webpack 中自动省略部分代码,计算数值,简化代码。 ```js let a = 1; let b = 2; let c = 3; let d = a + b + c; console.log(d + "------"); ``` 经过 webpack 打包后,会自动计算出结果,打包文件会直接输出 `console.log(6+'------')` 。 --- ## webpack 抽离公共代码 剥离代码块 > 从 webpack v4 开始,移除了 CommonsChunkPlugin,取而代之的是 optimization.splitChunks 新建三个文件, `app1.js` , `app2.js` , `common.js` 。app1 和 app2 都导入了 common, 如果不采用抽离公共代码,打包后,app1 和 app2 都会包含 common 的代码。 其实此时,我们即可将 common 抽离为公共代码块,进行单独打包为一个文件,app1 和 app2 只需引入公共代码块,增加代码的可复用性。 ![RUNOOB 图标](./public/img/20211009-112126.png) 具体操作如下: 1. 剥离公共代码块 ```js /* 具体配置参数查看webpack官网 */ module.exports = { optimization: { splitChunks: { cacheGroups: { common: { // filename: "common.js", name: "commons", chunks: "initial", minChunks: 2, minSize: 0, }, }, }, }, }; ``` > 提示:在代码复用性不高,公共代码不多时使用抽离公共代码,反而会增加构建包的体积。例如本例中, 公共代码块很简单,体积不大,不需要剥离代码块,剥离后反而增加了构建包的体积。 2. 剥离第三方依赖库,第三方依赖库单独打包文件 ```js /* 具体配置参数查看webpack官网 */ module.export = { optimization: { splitChunks: { cacheGroups: { commons: { name: "chunk-common", chunks: "initial", priority: -20, minChunks: 2, minSize: 0, }, vendors: { name: `chunk-vendors`, test: /[\\/]node_modules[\\/]/, priority: -10, chunks: "initial", }, }, }, }, }; ``` 3. 以 vuecli4 为例 下图是 vuecli4 脚手架的 SplitChunksPlugin 配置。 ![RUNOOB 图标](./public/img/20211009-145539.png) 我们可以修改该配置,将 chunk-vendors 进一步剥离,以优化我们的首频加载速度。例如,我们可以将第三方组件库单独剥离出来,具体配置如下: ```js /* vue.config.js vuecli4.0 */ module.exports = { configureWebpack: (config) => { config.optimization = { splitChunks: { cacheGroups: { /* 将node_modules下依赖包单独打包 */ vendors: { name: "chunk-vendors", test: /[\\/]node_modules[\\/]/, priority: -10, chunks: "initial", }, common: { /* 将复用两次以上的方法单独打包 */ name: "chunk-common", minChunks: 2, priority: -20, chunks: "initial", reuseExistingChunk: true, }, /* 将vant 单独打包 */ vant: { chunks: "all", name: `vant`, test: /[\\/]vant[\\/]/, priority: 0, }, }, }, }; }, }; ``` > 使用 SplitChunks 插件来剥离公共代码块单独打包有利有弊,好处在于,防止模块被重复打包,拆分过大的 js 文件,合并零散的 js 文件。缺点即为剥离越彻底,打包后的文件越多,增加浏览器的请求次数,故要以项目实际的情况去使用 SplitChunks 插件,需切记中庸之道。 参考文献:[webpack 之 SplitChunks 插件用法详解](https://juejin.cn/post/6844904198023168013) --- ## 懒加载 > es6 草案中的语法,jsonp 实现动态加载文件。如 vue 路由懒加载,react 懒加载都是采用的这种方式。 ```js /* 主要代码 */ /* source.js */ export default "我是资源文件"; /* index.js */ import("./source.js").then((data) => { console.log(data.default); }); ``` # 热更新 HRM > webpack5 默认支持 HRM > 在开发环境,可以将 HMR 作为 LiveReload 的替代。webpack-dev-server 支持 hot 模式,在试图重新加载整个页面之前,hot 模式会尝试使用 HMR 来更新。