讀了《深刻淺出webpack》總結一下經常使用的webpack的構建優化策略,可經過如下手段來提高項目構建時的速度node
將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
當咱們使用webpack
的watch
功能進行文件監聽時,更好的方式是控制監聽目錄,以下,排除node_modules
減小對該目錄監聽,減小編譯所須要循環的文件,提升檢查速度
module.export = { watchOptions: { ignored: /node_modules/ } }
默認的這個值查找方式見官網點擊此處
看了下react
和lodash
,只有一個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') } }
原理見補充6
默認狀況下,應用程序啓用內聯模式(inline mode)。這意味着一段處理實時重載的腳本被插入到你的包(bundle)中,而且構建消息將會出如今瀏覽器控制檯。
當使用inline
模式時,devServer
會向每一個Chunk
中注入一段重載的腳本代碼,可是其實一個頁面只須要一次,因此當Chunk
過多時,能夠將inline
設置爲false
module.export = { devServer: { inline: false } }
當有設置cacheDirectory
時,指定的目錄將用來緩存loader
的執行結果。以後的 webpack 構建,將會嘗試讀取緩存,來避免在每次執行時,可能產生的、高性能消耗的Babel
從新編譯過程。若是設置了一個空值 (loader: 'babel-loader?cacheDirectory') 或者 true (loader: babel-loader?cacheDirectory=true),loader 將使用默認的緩存目錄 node_modules/.cache/babel-loader,若是在任何根目錄下都沒有找到 node_modules 目錄,將會降級回退到操做系統默認的臨時文件目錄。
node_modules
目錄,看是否有匹配項,若有,命中文件node_modules
,若有,命中文件node_modules
大量項目中能夠複用的模塊只須要被編譯一次,在以後的構建過程當中被動態連接庫包含的模塊將不會從新編譯,而是直接使用動態連接庫中的代碼。(注:若是升級依賴的模塊版本,須要從新編譯動態連接庫)
webpack
構建中,須要大量的loader轉換操做,很耗時,因爲nodejs是單線程的,若是想更好利用cpu的多核能力,能夠開啓多個進程,同時對文件進行處理;能夠看到在配置文件中,咱們每次將文件交給happypack-loader
去處理,而後由happypack
去調度來執行文件的處理(happypack
採用哪一個loaders
進行處理,是經過id
知道的)
webpack
會從入口觸發,將全部的依賴項放到一個list裏邊,而後每次修改文件內容,回去遍歷整個list裏邊的文件,看是否有編輯時間的變化,若是有的話則進行編譯