把你的devtools從webpack裡刪除

諸葛林發表於2019-04-17

移動端除錯不是總能 inspect 一通的,為此我們引入了騰訊的萬金油 vConsole。開發時固然蛋定,釋出時卻有點操蛋。

開始的使用

通過判斷是否為 dev 環境,載入 vConsole 並例項化使用:

// 開發時引入 vConsole
if (process.env.NODE_ENV === 'development') {
  // 吐槽一波:不支援 import 方式
  const VConsole = require('vconsole');
  new VConsole();
}
複製程式碼

生產環境是沒有 vConsole 了吧!想象很豐滿,打包很骨感。

如果你 splitChunks 了的話,打包後的檔案多出了個 vConsole,約 90k。使用 webpack-bundle-analyzer 分析也會看到多出一大塊。。。

在這個移動端分秒必爭的時代,凡是能從程式碼層面上優化的沒理由不做。

> 每次合併到主分支時註釋再提交,像下面這樣[笑哭]

// 開發時引入 vConsole
// if (process.env.NODE_ENV === 'development') {
//   // 吐槽一波:不支援 import 方式
//   const VConsole = require('vconsole');
//   new VConsole();
// }

> 每次開發時再去掉註釋,丟你煤泥~
複製程式碼

碼·格瓦拉:“優化是不可能不優化的,這輩子都不可能不優化的。”

定義瀏覽器端環境變數

啟動時 NODE_ENV=development webapck 這樣定義的環境變數只在 node 執行 webpack 時生效,通過 process.env 訪問。簡而言之,只能在 webpack.config.js 中判斷 dev/prod。

所以實現之前的程式碼邏輯我們需要 DefinePlugin。使用時:

// webpack.config.js
const webpack = require('webpack');

module.exports ={
  plugins: [
    new webpack.DefinePlugin({
      __DEV__: JSON.stringify(false),
    }),
  ],
};
複製程式碼

引入 vConsole 的方式基本不變:

// index.js
// __DEV__ 就是 DefinePlugin 注入的全域性常量
// 開發時引入 vConsole
if (__DEV__) {
  // 吐槽一波:不支援 import 方式
  const VConsole = require('vconsole');
  new VConsole();
}

// 打包後的程式碼長這樣:
// 看起來這外掛就是執行文字替換的功能
if (false) {
  // 吐槽一波:不支援 import 方式
  const VConsole = require('vconsole');
  new VConsole();
}
複製程式碼

程式碼邏輯實現了,但是 vConsole 依舊在打包檔案裡。這時候就要藉助我們功能強大的程式碼壓縮。

程式碼壓縮

webpack v4 版本設定為 mode: 'production' 後預設即啟用程式碼壓縮。

以前推薦的是 UglifyjsWebpackPlugin,底層 uglify-js,但是隻支援 ES5,所以倉庫上還有個 harmony 分支用來處理 ES6,webpack 外掛用的也是這個分支。但是這個分支已經長時間沒人維護了,所以官方轉到另一個 TerserWebpackPlugin,兩個外掛基本一模一樣。

手動啟用:

module.exports = {
  optimization: {
    minimize: true
  },
};

// 或者直接覆蓋自帶的,可進行顆粒度的控制
const TerserWebpackPlugin = require('terser-webpack-plugin');

module.exports = {
  optimization: {
    minimizer: [
      new TerserWebpackPlugin({
        terserOptions: {
          compress: {
            dead_code: true, // 預設。刪除不可到達的程式碼
          },
        },
      });
    ],
  },
};
複製程式碼

而我們需要的就是其刪除 dead code 功能,類似下面這樣的就是 dead code:

----------------------------
| if (false) alert('你好'); | // 一塊 dead code
----------------------------
複製程式碼

實際使用可能需要進行判斷,但是有點坑。

statement dead_code 支援
true/false
1 === 2
'a' !== 'a'
'a' !== 'b'
undefined/null
  1. Boolean/Number 支援可寫表示式判斷
  2. String 只支援完全相同的兩字串判斷,不同字串不支援
  3. Undefined/Null 不支援

最後

使用 DefinePlugin + TerserWebpackPlugin 配置,打包後發現 vConsole 沒了。可以向老闆申請加雞腿了······

小貼士:ProvidePluginexternals 的區別,前者自動 import,後者是無需 npm install 即可直接 import

參考連結

  1. webpack選擇性編譯DefinePlugin(打包自動剔除測試資料)
  2. webpack的打包和效能優化
  3. webpack更新至4.26

相關文章