利用 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