webpack常用構建優化總覽

簡介

讀了《深入淺出webpack》總結一下常用的webpack的構建優化策略,可通過以下手段來提升項目構建時的速度

更精準的loader規則

將loader規則寫清楚

僅讓需要處理的文件,進入loader處理環節,如下

    rules: [{
      // 正則盡量準確
      test: /\.js$/,
      // 使用緩存,緩存后在文件未改變時編譯會更快(緩存查找原理見補充1)
      use: ['babel-loader?cacheDirectory'],
      // 指定需要處理的目錄
      include: path.resolve(__dirname, 'src')
      // 理論上只有include就夠了,但是某些情況需要排除文件的時候可以用這個,排除不需要處理文件
      // exclude: []
    }]

更精準的查找目錄

將查找路徑設置精確

理論上我們項目的第三方依賴均應在自己的工程的node_modules下,所以我們可以設置查找目錄,減少node的默認查找(默認查找方式見補充2)

module.exports = {
    resolve: {
        // 指定當前目錄下的node_modules目錄
        modules: [path.resolve(__dirname, 'node_modules')]
    }
}

更精準的擴展名

數量更多類型的文件盡量放在前面

平時寫代碼,我們都習慣直接寫文件名,而不去寫擴展名,那么解析則按照下面屬性進行解析

module.exports = {
    extensions: ['.js', '.jsx', '.ts', '.tsx'],
}

默認值

extensions: [".js", ".json"]

使用動態鏈接庫預編譯大模塊

使用動態鏈接庫,提前編譯大模塊

原理請見補充3

新建一個文件webpack_dll.config.js,內容如下

const path = require('path');
const webpack = require('webpack');

// 復用的大模塊放在這里,這樣每次都不需要重新編譯了
const vendors = [
  'react',
  'react-dom',
  'lodash'
];

module.exports = {
  mode: 'development',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: '[name].js',
    library: '[name]',
  },
  entry: {
    vendors,
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.resolve(__dirname, './dist/manifest.json'),
      name: '[name]',
    }),
  ],
};

執行webpack --config webpack_dll.config.js進行首次編譯(如果更新版本需要再次編譯)

然后在你的webpack配置文件中引入manifest.json

  plugins: [
    new webpack.DllReferencePlugin({
      manifest: require('./dist/manifest.json')
    })
  ],

多進程處理文件

使用HappyPack同時處理多個loader編譯任務

為了發揮多核CPU電腦的功能,利用HappyPack將任務分發給多個子進程并發執行

const path = require('path');
const HappyPack = require('happypack');
// 共享5個進程池
const happyThreadPool = HappyPack.ThreadPool({ size: 5 });

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    // noParse: [/react\.production\.min\.js$/],
    rules: [{
      test: /\.js$/,
      // 和下面插件id一直,happypack才可以找到
      use: ['happypack/loader?id=babel'],
      include: path.resolve(__dirname, 'src')
    }]
  },
  plugins: [
    // 插件可以實例化多個
    new HappyPack({
      // 與上面對應
      id: 'babel',
      // 實際要使用的loader
      loaders: ['babel-loader?cacheDirectory'],
      // 默認開啟進程數
      threads: 3,
      // 是否允許happyPack打印日志
      verbose: true,
      // 共享進程數,如果你使用超過一個happyplugin,官方建議共享進程池
      threadPool: happyThreadPool
    })
  ],
};

原理見補充4

多進程壓縮文件

使用ParallelUglifyPlugin多進程同時壓縮文件

ParallelUglifyPlugin是在UglifyJS基礎上,增加了多進出處理的能力,加快了壓縮速度

import ParallelUglifyPlugin from 'webpack-parallel-uglify-plugin';
 
module.exports = {
  plugins: [
    new ParallelUglifyPlugin({
      test,
      include,
      exclude,
      cacheDir,
      workerCount,
      sourceMap,
      uglifyJS: {
      },
      uglifyES: {
      }
    }),
  ],
};

減少監聽文件

減少監聽文件

原理見補充5

當我們使用webpackwatch功能進行文件監聽時,更好的方式是控制監聽目錄,如下,排除node_modules減少對該目錄監聽,減少編譯所需要循環的文件,提高檢查速度

module.export = {
    watchOptions: {
        ignored: /node_modules/
    }
}

其他沒那么重要的優化

更精準的mainFields

默認的這個值查找方式見官網點擊此處

看了下reactlodash,只有一個main,目前來看使用es6看來還不普遍,所以這個值目前可能不太重要

module.exports = {
    resolve: {
        mainFields: ['main']
    }
}

第三方庫映射

為什么這個不重要,我發現react直接導出的index.js則是根據環境判斷使用哪份代碼,目測來看并不需要進行循環依賴的處理

通過依賴,則可以直接使用打包后代碼,而不需webpack去循環依賴

  resolve: {
    mainFields: ["main"],
    alias: {
      'react': path.resolve(__dirname, './node_modules/react/cjs/react.production.min.js')
    }
  }

不使用inline模式的devServer

原理見補充6

默認情況下,應用程序啟用內聯模式(inline mode)。這意味著一段處理實時重載的腳本被插入到你的包(bundle)中,并且構建消息將會出現在瀏覽器控制臺。

當使用inline模式時,devServer會向每個Chunk中注入一段重載的腳本代碼,但是其實一個頁面只需要一次,所以當Chunk過多時,可以將inline設置為false

module.export = {
    devServer: {
        inline: false
    }
}

補充

補充1-cacheDirectory原理

當有設置cacheDirectory時,指定的目錄將用來緩存loader的執行結果。之后的 webpack 構建,將會嘗試讀取緩存,來避免在每次執行時,可能產生的、高性能消耗的Babel重新編譯過程。如果設置了一個空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 將使用默認的緩存目錄 node_modules/.cache/babel-loader,如果在任何根目錄下都沒有找到 node_modules 目錄,將會降級回退到操作系統默認的臨時文件目錄。

補充2-node的默認查找方式

  1. 查找當前目錄下的node_modules目錄,看是否有匹配項,如有,命中文件
  2. 尋找父目錄的下的node_modules,如有,命中文件
  3. 按照這個規則一直往父目錄搜索直到到根目錄下的node_modules

補充3-動態鏈接庫思想

大量項目中可以復用的模塊只需要被編譯一次,在之后的構建過程中被動態鏈接庫包含的模塊將不會重新編譯,而是直接使用動態鏈接庫中的代碼。(注:如果升級依賴的模塊版本,需要重新編譯動態鏈接庫)

補充4-HappyPack原理

webpack構建中,需要大量的loader轉換操作,很耗時,由于nodejs是單線程的,如果想更好利用cpu的多核能力,可以開啟多個進程,同時對文件進行處理;可以看到在配置文件中,我們每次將文件交給happypack-loader去處理,然后由happypack去調度來執行文件的處理(happypack采用哪個loaders進行處理,是通過id知道的)

補充5-文件監聽原理

webpack會從入口觸發,將所有的依賴項放到一個list里邊,然后每次修改文件內容,回去遍歷整個list里邊的文件,看是否有編輯時間的變化,如果有的話則進行編譯

補充6-自動刷新原理

  • 向要開發的網頁中注入代理客戶端代碼,通過代理客戶端去刷新整個頁面(默認)
  • 將要開發的網頁放進一個iframe,通過刷新iframe去看刷新效果

你可能感興趣的

广东25选5开奖结果