Webpack 核心總結

前言

筆者最近從新複習了一遍 Webpack 核心功能,果真是溫故而知新!這篇文章結合高級進階之 Webpack 篇閱讀效果更佳!javascript

常見優化手段

構建速度優化

思路:縮小搜索範圍,減小沒必要要的模塊打包,加快構建(緩存,多線程)
縮少搜索範圍:css

  • 指定第三方目錄 resolve.modules,resolve.alias 緩存目錄,extensions 減小後綴的搜索
  • loader 配置指定編譯範圍 exclude/include

減小沒必要要的模塊打包:前端

  • 經過cdn引入(vue 全家桶)等,而後用externals 提取經常使用庫,不會再打包到 bundle 文件,並能夠經過import 引入;
  • 經過 DllPlugin、DllReferencePlugin 插件來預編譯模塊,減小沒必要要的打包

注意:在 Webpack5 中已經不⽤ DllPlugin、DllReferencePlugin 了,⽽是⽤ HardSourceWebpackPlugin 替代vue

const HardSourceWebpackPlugin = require('hard-source-webpack-plugin')
const plugins = [
 new HardSourceWebpackPlugin(
)
]
複製代碼

加快構建:java

  • 使用cache-loader進行緩存;
  • 使用 happypack 插件開啓多個線程打包資源文件(happypack再也不維護),能夠用 thread-loader 替代

性能優化

代碼壓縮 :
node

使用 ParallelUglifyPlugin 插件:開啓多線程對 js 文件壓縮和緩存,刪除多餘的註釋和 console.log
注意: 在生產環境下即配置中 mode 設置爲 production,webpack 默認開啓了 TerserWebpackPlugin 能夠實現該功能,若是須要剔除調試代碼能夠自行配置,具體參考下面的 TerserWebpackPlugin 配置
webpack

  1. 多進程並行壓縮
  • webpack-paralle-uglify-plugin
  • uglifyjs-webpack-plugin 開啓 parallel 參數 (不支持ES6)
  • terser-webpack-plugin 開啓 parallel 參數
  1. 經過 mini-css-extract-plugin 提取 Chunk 中的 CSS 代碼到單獨文件,經過 css-loader 的 minimize 選項開啓 cssnano 壓縮 CSS。
  2. 圖片壓縮 配置 image-webpack-loader


代碼分割緩存:
使用 optimization.splitChunks.cacheGroup 進行公共代碼分割抽離和緩存 es6

如何作 Tree Shaking

Webpack4.0 以上版本在 mode 爲 production 時,會自動開啓 Tree Shaking 能力。默認 production mode 的配置以下:web

const config = {
 mode: 'production',
 optimization: {
 usedExports: true,
 minimizer: [
  new TerserPlugin({...})
 ]
 }
};
複製代碼

什麼是反作用

"side effect(反作用)" 的定義是,在導入時會執行特殊行爲的代碼,而不是僅僅暴露一個 export 或多個 export。舉例說明,例如 polyfill,它影響全局做用域,而且一般不提供 export。面試

解決反作用:經過 package.json 的 "sideEffects" 屬性,來實現這種方式。

{
  "name": "your-project",
  "sideEffects": ["./src/some-side-effectful-file.js"]
}
複製代碼

若是你的代碼確實有一些反作用,能夠改成提供一個數組:

{
  "name": "your-project",
  "sideEffects": ["./src/some-side-effectful-file.js"]
}
複製代碼

loader 與 plugin 的區別

  • loader: loader是一個轉換器是在 import 或"加載"模塊時預處理文件,將A語言轉成B語言,如 TypeScript轉換爲 JavaScript,less 轉成 css,單純的文件轉換成瀏覽器能夠識別的文件。
  • plugin:插件是一個擴展器,能夠擴展 webpack 的功能,在 webpack 運行的生命週期會廣播許多鉤子,plugin 會監聽這些事件,在合適的時機經過 webapck API (run、compile、emit)等改變輸出結果。

webpack 熱更新原理

如下內容來自字節前端面試題

  1. 當修改了一個或多個文件;
  2. 文件系統接收更改並通知 webpack;
  3. webpack 從新編譯構建一個或多個模塊,並通知 HMR 服務器進行更新;
  4. HMR Server 使用 webSocket 通知 HMR runtime 須要更新,HMR 運行時
    經過 HTTP 請求更新 jsonp;
  5. HMR 運行時替換更新中的模塊,若是肯定這些模塊沒法更新,則觸發整
    個頁面刷新。

注意:啓動 HMR 後,css 抽離會不⽣效,還有不⽀持 contenthash,chunkhash

webapck 打包原理

高級進階之 Webpack 篇

重要配置代碼展現

webpack-paralle-uglify-plugin

// 使用 ParallelUglifyPlugin 並行壓縮輸出的 JS 代碼
    new ParallelUglifyPlugin({
      // 傳遞給 UglifyJS 的參數
      uglifyJS: {
        output: {
          // 最緊湊的輸出
          beautify: false,
          // 刪除全部的註釋
          comments: false,
        },
        compress: {
          // 在UglifyJs刪除沒有用到的代碼時不輸出警告
          warnings: false,
          // 刪除全部的 `console` 語句,能夠兼容ie瀏覽器
          drop_console: true,
          // 內嵌定義了可是隻用到一次的變量
          collapse_vars: true,
          // 提取出出現屢次可是沒有定義成變量去引用的靜態值
          reduce_vars: true,
        }
      },
    }),
複製代碼

uglifyjs-webpack-plugin

const UglifyJSPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
	optimization: {
		minimizer: [
			new UglifyJsPlugin({
				test: /\.js(\?.*)?$/i, //測試匹配文件,
				// include: /\/includes/, //包含哪些文件
				// exclude: /\/node_modules/, //不包含哪些文件
				//容許過濾哪些塊應該被uglified(默認狀況下,全部塊都是uglified)。
				//返回true以uglify塊,不然返回false。
				chunkFilter: chunk => {
				  // `vendor` 模塊不壓縮
				  if (chunk.name === "vendor") {
					return false;
				  }
				  return true;
				},
				cache: false, //是否啓用文件緩存,默認緩存在node_modules/.cache/uglifyjs-webpack-plugin.目錄
				parallel: true //使用多進程並行運行來提升構建速度
			})
		]
	},
}

// 等價於

{
    plugins: [    
            // 壓縮JS文件
            new UglifyJSPlugin({
                            test: /\.js(\?.*)?$/i, //測試匹配文件,
                            // include: /\/includes/, //包含哪些文件
                            // exclude: /\/node_modules/, //不包含哪些文件
                            //容許過濾哪些塊應該被uglified(默認狀況下,全部塊都是uglified)。
                            //返回true以uglify塊,不然返回false。
                            chunkFilter: chunk => {
                              // `vendor` 模塊不壓縮
                              if (chunk.name === "vendor") {
                                    return false;
                              }
                              return true;
                            },
                            cache: false, //是否啓用文件緩存,默認緩存在node_modules/.cache/uglifyjs-webpack-plugin.目錄
                            parallel: true //使用多進程並行運行來提升構建速度,不支持 es6
                    }),
    ],
}

複製代碼

terser-webpack-plugin

// webpack.config.js

// 導入terser-webpack-plugin-->減小js體積(其中刪除js的console.log和註釋)
const TerserWebpackPlugin = require('terser-webpack-plugin');
// 實例化TerserWebpackPlugin對象
const terserPlugin = new TerserWebpackPlugin({
  parallel: 4,
  extractComments: true,
  terserOptions: {
    compress: {
      warnings: false,
      drop_console: true,
      drop_debugger: true,
      pure_funcs: ['console.log'] //移除console
    }
  }
});

module.exports = {
	optimization: {
    	minimizer: [
      	// 只有打包環境爲production時才能生效
      	terserPlugin
    ],
  },
}

複製代碼

mini-css-extract-plugin

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: "css/[name].css",
      // chunkFilename: "[name].css",
      disable: isDebug
    }),],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};
複製代碼

optimization.splitChunks

splitChunks:{
        cacheGroups: {
            common:{
                chunks: 'initial',
                name:'Common', // 打包後的文件名
                minSize: 0, 
                minChunks: 2 // 重複2次才能打包到此模塊
            },
            vendor: {
                priority: 1, // 優先級配置,優先匹配優先級更高的規則,不設置的規則優先級默認爲0
                test: /node_modules/, // 匹配對應文件
                chunks: 'initial',
                name:'Vendor',
                minSize: 0,
                minChunks: 1
            }
        }
    }
複製代碼

熱更新實現

const path = require('path')
const webpack = require('webpack')
module.exports = {
    entry: './index.js',
    output: {
        filename: 'bundle.js',
        path: path.join(__dirname, '/')
    },
    devServer: {
        hot: true
    },
    plugins:[
    new webpack.HotModuleReplacementPlugin()
    ]
}
複製代碼

若是不使用 HotModuleReplacementPlugin 能夠直接 package.json 配置

"dev": "webpack-dev-server --hot --open"
複製代碼
相關文章
相關標籤/搜索