利用 Webpack 来优化 Web 性能属于_加载性能优化_的一部分: ☛ Web Performance Optimization with webpack
production
模式
production
模式下 webpack 会对代码进行优化,如减少代码体积,删除只在开发环境用到的代码。
能够在 webpack 中指定:css
module.exports = { mode: 'production' // 或 development };
或者 package.json 中配置:前端
"scripts": { "dev": "webpack-dev-server --mode development --open --hot", "build": "webpack --mode production --progress" }
使用 bundle-level minifier 和 loader options 压缩代码。
Bundle-level 的压缩会在代码编译后对整个包进行压缩。react
在 webpack 4 中,production
模式下会自动执行 bundle-level 的压缩,底层使用了 the UglifyJS minifier。(若是不想开启压缩,能够采用 development
模式或者设置 optimization.minimize
为 false)webpack
经过 loader 层面的选项配置来对代码进行压缩,是为了压缩 bundle-level minifier 没法压缩的内容,好比,经过 css-loader
编译后的文件,会成为字符串,就没法被 minifier 压缩。所以,要进一步压缩文件内容,可进行以下配置:git
// webpack.config.js module.exports = { module: { rules: [ { test: /\.css$/, use: [ 'style-loader', { loader: 'css-loader', options: { minimize: true } }, ], }, ], }, };
当使用 ES 模块时, webpack 可以进行 tree-shaking。tree-shaking 是指 bundler 遍历整个依赖关系树,检查使用了哪些依赖关系,并删除未使用的依赖关系。所以,若是使用ES模块语法,webpack 能够消除未使用的代码。github
★ 注意:在 webpack 中,若是没有 minifier,tree-shaking 就没法工做。webpack 只删除不使用的导出语句,而 minifier 则会删除未使用的代码。所以,若是在编译时不使用 minifier,代码量并不会减少。(除了使用 wbpack 内置的 minifier,其它的插件如 Babel Minify plugin 也能对代码进行压缩)。web
✘ 警告:不要意外地将 ES 模块编译成 CommonJS 模块。若是你使用 Babel 的时候,采用了 babel-preset-env
或者 babel-preset-es2015
,请检查这些预置的设置。默认状况下,它们会将 ES 的导入和导出转换为 CommonJS 的 require
和 module.exports
,能够经过传递 { modules: false }
选项来禁用它。json
➹ Introduction to ES Modules
➹ 一口(很长的)气了解 babel
➹ Webpack docs about tree shaking浏览器
针对具体的依赖项进行优化( dependency-specific optimization)图像占了页面大小的一半以上。虽然它们不像JavaScript那样重要(例如,它们不会阻塞呈现),但它们仍然占用了很大一部分带宽。在 webpack 中可使用
url-loader
、svg-url-loader
和image-webpack-loader
来优化它们。性能优化
url-loader
能够将小型静态文件内联到应用程序中。若是不进行配置,它将把接受一个传递的文件,将其放在已编译的包旁边,并返回该文件的url。可是,若是指定 limit 选项,它将把小于这个限制的文件编码为Base64 数据的 url 并返回这个url,这会将图像内联到 JavaScript 代码中,从而能够减小一个HTTP请求。
// webpack.config.js module.exports = { module: { rules: [ { test: /\.(jpe?g|png|gif)$/, loader: 'url-loader', options: { // Inline files smaller than 10 kB (10240 bytes) limit: 10 * 1024, }, }, ], } };
// index.js import imageUrl from './image.png'; // → If image.png is smaller than 10 kB, `imageUrl` will include // the encoded image: 'data:image/png;base64,iVBORw0KGg…' // → If image.png is larger than 10 kB, the loader will create a new file, // and `imageUrl` will include its url: `/2fcd56a1920be.png`
★ 注意:须要在增大代码体积和减小 HTTP 请求数以前进行权衡。
svg-url-loader
的工做原理与 url-loader
相似 — 只是它使用的是URL编码而不是Base64编码来编码文件。这对SVG图像颇有用 — 由于SVG文件只是纯文本,这种编码更高效。
// webpack.config.js module.exports = { module: { rules: [ { test: /\.svg$/, loader: 'svg-url-loader', options: { // Inline files smaller than 10 kB (10240 bytes) limit: 10 * 1024, // Remove the quotes from the url // (they’re unnecessary in most cases) noquotes: true, }, }, ], }, };
★ 注意: svg-url-loader
有一些选项能够改进Internet Explorer的支持,但会使其余浏览器的内联更加糟糕。若是须要支持此浏览器,请应用 iesafe: true
选项。
image-webpack-loader
可支持JPG、PNG、GIF和SVG图像的压缩。
这个加载器不嵌入图像到应用程序,因此它必须与 url-loader
和 svg-url-loader
成对工做。为了不将其复制粘贴到两个规则中(一个用于JPG/PNG/GIF图像,另外一个用于SVG图像),咱们经过 enforce: 'pre' 将这个加载器设为一个单独的规则:
// webpack.config.js module.exports = { module: { rules: [ { test: /\.(jpe?g|png|gif|svg)$/, loader: 'image-webpack-loader', // This will apply the loader before the other ones enforce: 'pre', }, ], }, };
JavaScript 的大小平均有一半以上来自依赖项,而其中的一部分多是没必要要的。咱们能够对这些依赖的库进行优化➡️ webpack-libs-optimizations。
好比:moment.js 删除未使用的地区、react-router 移除未使用的模块,生产环境去除 react propTypes 声明等。
也叫作做用域提高(Scope Hoisting)
早期的时候,为了隔离 CommonJS/AMD 模块,webpack 在打包的时候,会把每一个模块都打包到一个函数中,这样就会增大每一个模块的大小和性能开销。webpack 2 的时候支持了 ES 模块,而后 webpack 3 的时候使模块链接成为了可能。
【原理】:它会分析模块间的依赖关系,尽量将被打散的模块合并到一个函数中,但不能形成代码冗余,因此只有被引用一次的模块才能被合并。因为须要分析模块间的依赖关系,因此源码必须是采用了ES6模块化的,不然Webpack会降级处理不采用Scope Hoisting。
开启模块链接以后,打出的包将会具备更少的模块,以及更少的模块开销。若是在生产模式下使用 webpack 4,则模块链接已经启用。
// webpack.config.js (for webpack 4) module.exports = { optimization: { concatenateModules: true, }, };
★ 注意:为何默认状况下不启用此行为?链接模块很酷,可是它增长了构建时间,并中断了热模块替换。这就是为何应该只在生产中启用它。
externals