打包发现 js(main.8983191438.js) 没有变,只有 css 变了:
> npm run build > webpack-example3@1.0.0 build > webpack Hash: 1598c3794090ebc6964c Version: webpack 4.46.0 Time: 4905ms Built at: 2021-07-14 9:31:14 ├F10: PM┤ Asset Size Chunks Chunk Names index.html 417 bytes [emitted] main.0241bb73c4.css 13 bytes main [emitted] [immutable] main main.8983191438.js 5.22 KiB main [emitted] [immutable] main再次通过浏览器访问,发现 css 请求了新的文件,而 js 还是来自缓存。
Tip: 是否要将 hash 清除?
注:此刻运行 npm run build 会报错,为了不影响下面的介绍,所以将 hash 去除,source map 也不需要,一并删除。
ERROR in chunk main [entry] Cannot use [chunkhash] or [contenthash] for chunk in 'main.[contenthash:10].js' (use [hash] instead) tree shakingtree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。
使用树摇非常简单,只需要满足两个条件:
使用 es6 模块化
模式(mode)开启production
直接演示,请看:
a.js 中导出 a 和 b,但在index.js 中只使用了a:
// a.js export let a = 'hello' export let b = 'jack' // index.js import { a } from './a.js' console.log(a);首先在开发模式下测试,发现 a.js 中的”hello“和”jack“都打包进去了,请看示例:
module.exports = { mode: 'development', } // dist/main.js // a 和 b 都被打包进来,尽管 b 没有被用到 var a = 'hello'; var b = 'jack';而在生成模式下,只有用到的 a 才被打包进去,请看示例:
module.exports = { mode: 'production', } // dist/main.js // 只找到 hello,没有找到 jack console.log("hello") 将文件标记为 side-effect-free(无副作用)在一个纯粹的 ESM 模块世界中,很容易识别出哪些文件有副作用。然而,我们的项目无法达到这种纯度,所以,此时有必要提示 webpack compiler 哪些代码是“纯粹部分”。
通过 package.json 的 "sideEffects" 属性,来实现这种方式。
{ "sideEffects": false }如果所有代码都不包含副作用,我们就可以简单地将该属性标记为 false,来告知 webpack 它可以安全地删除未用到的 export。
Tip:"side effect(副作用)" 的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个 export 或多个 export。举例说明,例如 polyfill,它影响全局作用域,并且通常不提供 export。
我们通过一个例子说明下:
在入口文件引入 css 文件:
// index.js import './a.css' import { a } from './a.js' console.log(a); // a.css p{color:yellow;} // webapck.config.js mode: 'production'打包会生成 css:
> npm run build Asset Size Chunks Chunk Names index.html 342 bytes [emitted] main.css 13 bytes 0 [emitted] main main.js 1.3 KiB 0 [emitted] main在 package.json 添加 "sideEffects": false,标注所有代码都不包含副作用:
{ "sideEffects": false }再次打包,则不会生成 css:
> npm run build Asset Size Chunks Chunk Names index.html 303 bytes [emitted] main.js 1.3 KiB 0 [emitted] main注:所有导入文件都会受到 tree shaking 的影响。这意味着,如果在项目中使用类似 css-loader 并 import 一个 CSS 文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
// package.json { "sideEffects": [ "*.css", "*.less" ] } 代码分割将一个文件分割成多个,加载速度可能会更快,而且分割成多个文件后,还可以实现按需加载。
optimization.splitChunks对于动态导入模块,默认使用 webpack v4+ 提供的全新的通用分块策略(common chunk strategy) —— SplitChunksPlugin。
开箱即用的 SplitChunksPlugin 对于大部分用户来说非常友好。
webpack 将根据以下条件自动拆分 chunks:
新的 chunk 可以被共享,或者模块来自于 node_modules 文件夹
新的 chunk 体积大于 20kb(在进行 min+gz 之前的体积)
当按需加载 chunks 时,并行请求的最大数量小于或等于 30
当加载初始化页面时,并发请求的最大数量小于或等于 30
Tip: SplitChunksPlugin的默认配置如下:
// webpack.config.js module.exports = { optimization: { splitChunks: { chunks: 'async', minSize: 20000, minRemainingSize: 0, minChunks: 1, maxAsyncRequests: 30, maxInitialRequests: 30, enforceSizeThreshold: 50000, cacheGroups: { defaultVendors: { test: /[\\/]node_modules[\\/]/, priority: -10, reuseExistingChunk: true, }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true, }, }, }, }, };默认配置很多,如果我们不需要修改,则不用管它们,下面我们来体验一下 splitChunks.chunks: