webpack經常使用構建優化總覽

簡介

讀了《深刻淺出webpack》總結一下經常使用的webpack的構建優化策略,可經過如下手段來提高項目構建時的速度node

更精準的loader規則

將loader規則寫清楚react

僅讓須要處理的文件,進入loader處理環節,以下webpack

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

更精準的查找目錄

將查找路徑設置精確es6

理論上咱們項目的第三方依賴均應在本身的工程的node_modules下,因此咱們能夠設置查找目錄,減小node的默認查找(默認查找方式見補充2)web

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

更精準的擴展名

數量更多類型的文件儘可能放在前面json

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

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

默認值緩存

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

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

使用動態連接庫,提早編譯大模塊babel

原理請見補充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去看刷新效果
相關文章
相關標籤/搜索