1. 程式人生 > >webpack配置之代碼優化

webpack配置之代碼優化

import ont name splitting lB jquer fault 內聯 javascrip

前面的話

  前面介紹了webpack的基本配置,本文將詳細介紹webpack中關於代碼優化的配置

打包公共代碼

  CommonsChunkPlugin 插件,是一個可選的用於建立一個獨立文件(又稱作 chunk)的功能,這個文件包括多個入口 chunk 的公共模塊。通過將公共模塊拆出來,最終合成的文件能夠在最開始的時候加載一次,便存到緩存中供後續使用。這會帶來速度上的提升,因為瀏覽器會迅速將公共的代碼從緩存中取出來,而不是每次訪問一個新頁面時,再去加載一個更大的文件

new webpack.optimize.CommonsChunkPlugin(options)

【配置項】

{
  name: string, // or
  names: string[],
  // common chunk 的名稱
filename: string, // common chunk 的文件名模板。可以包含與 `output.filename` 相同的占位符 minChunks: number|Infinity|function(module, count) -> boolean, // 在傳入公共chunk(commons chunk) 之前所需要包含的最少數量的 chunks 。 // 數量必須大於等於2,或者少於等於 chunks的數量 chunks:
string[], // 通過 chunk name 去選擇 chunks 的來源。chunk 必須是 公共chunk 的子模塊。
children: boolean, // 如果設置為 `true`,所有公共chunk 的子模塊都會被選擇 deepChildren: boolean, // If `true` all descendants of the commons chunk are selected async: boolean|string, // 如果設置為 `true`,一個異步的公共chunk 會作為 `options.name` 的子模塊,和 `options.chunks` 的兄弟模塊被創建。
minSize: number, // 在 公共chunk 被創建立之前,所有公共模塊 (common module) 的最少大小。 }

【提取公共代碼】

new webpack.optimize.CommonsChunkPlugin({
  name: "commons",
  // ( 公共chunk(commnons chunk) 的名稱)

  filename: "commons.js",
  // ( 公共chunk 的文件名)
})

【明確第三方庫chunk】

entry: {
  vendor: ["jquery", "other-lib"],
  app: "./entry"
},
plugins: [
  new webpack.optimize.CommonsChunkPlugin({
    name: "vendor",
    minChunks: Infinity,
  })
]

【將公共模塊打包進父 chunk】

new webpack.optimize.CommonsChunkPlugin({
  children: true,
})

【額外的異步公共chunk】

new webpack.optimize.CommonsChunkPlugin({
  name: "app",
  // or
  names: ["app", "subPageA"]
  children: true,
  async: true,
  minChunks: 3,
})

【wepack4】

  webpack 4 將移除 CommonsChunkPlugin, 取而代之的是兩個新的配置項 optimization.splitChunks 和 optimization.runtimeChunk

  通過設置 optimization.splitChunks.chunks: "all" 來啟動默認的代碼分割配置項

  當滿足如下條件時,webpack 會自動打包 chunks:

當前模塊是公共模塊(多處引用)或者模塊來自 node_modules
當前模塊大小大於 30kb
如果此模塊是按需加載,並行請求的最大數量小於等於 5
如果此模塊在初始頁面加載,並行請求的最大數量小於等於 3

  通過設置 optimization.runtimeChunk: true 來為每一個入口默認添加一個只包含 runtime 的 chunk

動態導入

  上面介紹的CommonsChunkPlugin可以去重和分離chunk。而本節介紹的動態導入,則是通過模塊的內聯函數調用來分離代碼

  webpack 提供了兩個類似的技術。對於動態導入,第一種,也是優先選擇的方式是,使用符合 ECMAScript 提案 的 import() 語法。第二種,則是使用 webpack 特定的 require.ensure

  下面來使用import()語法來進行動態導入

  const path = require(path);
  const HTMLWebpackPlugin = require(html-webpack-plugin);

  module.exports = {
    entry: {
      index: ./src/index.js
    },
    plugins: [
      new HTMLWebpackPlugin({
        title: Code Splitting
     })
    ],
    output: {
      filename: [name].bundle.js,
      chunkFilename: [name].bundle.js,
      path: path.resolve(__dirname, dist)
    }
  };

  下面來動態導入loadsh

 function getComponent() { 
 return import(/* webpackChunkName: "lodash" */ lodash).then(_ => { var element = document.createElement(div); element.innerHTML = _.join([Hello, webpack], ); return element; }).catch(error => An error occurred while loading the component); } getComponent().then(component => { document.body.appendChild(component); })

  在註釋中使用了 webpackChunkName。這樣做會導致bundle 被命名為 lodash.bundle.js ,而不是 [id].bundle.js

懶加載

  懶加載或者按需加載,是一種很好的優化網頁或應用的方式。這種方式實際上是先把你的代碼在一些邏輯斷點處分離開,然後在一些代碼塊中完成某些操作後,立即引用或即將引用另外一些新的代碼塊。這樣加快了應用的初始加載速度,減輕了它的總體體積,因為某些代碼塊可能永遠不會被加載

  上面通過動態導入的loadsh確實會在腳本運行的時候產生一個分離的代碼塊 lodash.bundle.js ,在技術概念上“懶加載”它。問題是加載這個包並不需要用戶的交互 -- 意思是每次加載頁面的時候都會請求它

  下面來增加一個交互,當用戶點擊按鈕的時候用 console 打印一些文字。但是會等到第一次交互的時候再加載那個代碼塊(print.js

//print.js
console.log(The print.js module has loaded! See the network tab in dev tools...);
export default () => {
  console.log(Button Clicked: Here\‘s "some text"!);
}
//index.js
 import _ from lodash;
 function component() {
   var element = document.createElement(div);
   var button = document.createElement(button);
   var br = document.createElement(br);
   button.innerHTML = Click me and look at the console!;
   element.innerHTML = _.join([Hello, webpack],  );
   element.appendChild(br);
   element.appendChild(button);
   button.onclick = e => import(/* webpackChunkName: "print" */ ./print).then(module => {
     var print = module.default;
     print();
   });
    return element;
  }
 document.body.appendChild(component());

剔除無用代碼

  tree shaking 是一個術語,通常用於描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴於 ES2015 模塊系統中的靜態結構特性,例如 import 和 export。這個術語和概念實際上是興起於 ES2015 模塊打包工具 rollup

【JS】

  JS的tree shaking主要通過uglifyjs插件來完成

npm install --save-dev uglifyjs-webpack-plugin
const path = require(path);
const UglifyJSPlugin = require(uglifyjs-webpack-plugin);

module.exports = {
  entry: ./src/index.js,
  output: {
    filename: bundle.js,
    path: path.resolve(__dirname, dist)
 },
  plugins: [
   new UglifyJSPlugin()
  ]
};

【CSS】

  CSS的tree shaking主要通過purify CSS來實現的

npm i -D purifycss-webpack purify-css
const path = require(path);
const glob = require(glob);
const ExtractTextPlugin = require(extract-text-webpack-plugin);
const PurifyCSSPlugin = require(purifycss-webpack);

module.exports = {
  entry: {...},
  output: {...},
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallbackLoader: style-loader,
          loader: css-loader
        })
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin([name].[contenthash].css),
    // Make sure this is after ExtractTextPlugin!
    new PurifyCSSPlugin({
      // Give paths to parse for rules. These should be absolute!
      paths: glob.sync(path.join(__dirname, app/*.html)),
    })
  ]
};

  如果要設置多路徑,則需要將glob換成glob-all

const glob = require(glob-all);
paths: glob.sync([
  path.join(__dirname, .php),
  path.join(__dirname, partials/.php)
])

webpack配置之代碼優化