Webpack 構建性能優化之旅

目前負責的項目,是未經過腳手架和其餘框架搭建的 react 項目。開發過程當中,啓動項目和熱更新速度都不是很理想;打包構建時,速度也比較緩慢且因爲單個文件過大,用戶在訪問時,加載動畫的時間也比較長。因此打算對其進行部分優化工做。 本着提高 webpack 性能,最直接的方式就是升級 webpack 版本的思路。對項目中的進行了一系列的升級和優化。升級和優化的結果以下: QQ截圖20210528180306.png 編譯速度方面:javascript

  • 開發啓動項目的速度提高了(非修改配置/初次編譯)1180%;
  • 開發過程當中代碼熱更新速度變化不大,但開發體驗更好,瀏覽器更新進行局部更新而不是 reload;
  • 生產環境打包構建的速度提高了(非修改配置/初次編譯)201%。

體積方面:css

  • 項目中的兩個大文件體積分別減小了 77%和 86% 左右,大大加快了頁面的加載速度。

查看性能相關的插件:java

  • speed-measure-webpack-plugin測量 plugin、loader 等時間;
  • webpack-bundle-analyzer打包分析工具。

根據官方遷移文檔升級

  1. 升級Node.js ,至少 10.13.0 版本;
  2. 升級 webpack 4 及其相關的plugin/loader;
    • 升級 webpack 4 至最新版本,升級 webpack-cli 至最新版本;
    • 升級使用的 plugin 和 loader 爲最新版本。
// 檢查過期的依賴包
npm outdated
// 安裝最新版本依賴包
npm install package@latest
複製代碼
  1. 獲取堆棧信息中的棄用警告;
// 若是不存在默認的 webpack.config.js 配置,則須要 --config 指定配置文件
node --trace-deprecation node_modules/webpack/bin/webpack.js
複製代碼
  1. 測試 webpack5 兼容性

添加如下配置選項,檢查構建是否正常運行(完成後刪除這些配置選項)。node

module.exports = {
  node: {
    Buffer: false,
    process: false
  },
}
複製代碼
  1. 升級至 webpack5
npm install webpack@latest -D
複製代碼
  1. babel 升級到7,升級指南:連接。以及相應的插件。

具體注意事項查看官方遷移指南:To v5 from v4react

升級後調整和優化

調整

  1. 使用asset代替file-loader url-loader raw-loader
  2. JavaScript 代碼壓縮使用 webpack5 內置的terser-webpack-plugin

優化編譯和開發速度

  1. cache: filesystem持久緩存。可以大大提高二次構建速度(修改配置文件除外)。
{
	cache: {
        type: "filesystem",
        buildDependencies: {
            // config 添加爲 buildDependency,以便在改變 config 時得到緩存無效
            config: [__filename],
        },
        name: process.env.NODE_ENV,
        version: "1.0.0",
    },
}
複製代碼
  1. 使用thread-loader進行多進程構建。
// worker 啓動有必定的消耗,
// 能夠預熱 worker 池
const jsWorkerPool = {
    workerParallelJobs: 80,
    poolTimeout: 2000,
};
const cssWorkerPool = {
    workerParallelJobs: 10,
    poolTimeout: 2000,
};

threadLoader.warmup(jsWorkerPool, ["babel-loader"]);
threadLoader.warmup(cssWorkerPool, ["css-loader", "less-loader"]);
複製代碼
  1. 開發時,自動保存代碼致使構建頻繁且會報錯,又不想手動保存,則能夠開啓延遲構建。
devServer: {
  ...
  watchOptions: {
    // 延遲構建
    aggregateTimeout: 1500,
    ignored: /node_modules/,
  },
},
複製代碼
  1. css 模塊熱替換:css 藉助style-loader,能夠實現模塊熱替換;
  2. JavaScript 模塊熱替換:可使用社區的庫或插件實現,不然會經過 reload 的方式刷新。
    1. 若是符合如下條件,可以使用[react-refresh-webpack-plugin](https://github.com/pmmmwh/react-refresh-webpack-plugin)插件;

QQ截圖20210528173521.png

{
	plugins: [
  	new ReactRefreshWebpackPlugin()
  ]
}
複製代碼
  1. 若不符合上面的條件,可以使用react-hot-loader
// .babelrc
{
    "plugins": [
      	...,
        "react-hot-loader/babel"
    ]
}
// index.js
import { hot } from 'react-hot-loader';
...
const App = hot(module)(() => ...);
render(<App />, document.getElementById('root'));
複製代碼

優化編譯體積

打包後體積優化,主要是使用 Gzip 壓縮,將打包後體積較大的文件使用 Gzip 壓縮。項目中的兩個大文件體積分別減小了 77%和 86% 左右,大大加快了頁面的加載速度。 QQ截圖20210528171118.pngwebpack

Gzip 壓縮

Gzip(GNU- ZIP) 是一種壓縮技術。通過壓縮的頁面能大大加快瀏覽器端的加載速度。 啓用 Gzip 須要服務器端和瀏覽器端都支持:服務器端壓縮(提供壓縮的文件),瀏覽器端解壓。 注意:git

  • 圖片/mp3 等沒必要壓縮,壓縮率較小;
  • 使用 proxy_pass 反向代理頁面,gzip——http_version 須要修改成 1.0;
  • 靜態壓縮:gzip_static on;
  • 動態壓縮:gzip on。

其餘

其餘體積優化須要修改業務相關代碼較多,就暫未進行優化。github

遇到坑以及相關解決

  1. DeprecationWarning:[DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK] DeprecationWarning: Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader

speed-measure-webpack-plugin插件兼容性問題,目前尚未徹底和 webpack5 兼容,能夠在優化完成後移除相關配置。web

  1. Error: Cannot find module 'webpack-cli/bin/config-yargsnpm

    4.X版本的 webpack-cli 移除了yargs包,須要使用 webpack serve啓動webpack-dev-server

// package.json
{
	"script": {
		"dev": "webpack serve --config webpack.dev.js"
	}
}
複製代碼
  1. Support for the experimental syntax 'classProperties' isn't currently enabled

@babel/preset-env不包含小於 Stage 3 的語法提案,須要手動安裝相應插件。須要安裝插件@babel/plugin-proposal-class-properties

//.babelrc
{
  "plugin":[
  	"@babel/plugin-proposal-class-properties"
  ]
}
複製代碼
  1. Support for the experimental syntax 'decorators-legacy' isn't currently enabled

緣由同上,須要安裝插件@babel/plugin-proposal-decorators

//.babelrc
{
  "plugin":[
  	["@babel/plugin-proposal-decorators", {"legacy": true}]
  ]
}
複製代碼
  1. expose-loader升級後,報錯:ValidationError: Invalid options object. Expose Loader has been initialized using an options object that does not match the API schema.
// webpack 配置文件
module: {
	rules:[
  	...,
    {
    	use: {
    		loader: "expose-loader",
    		options: {
    				exposes: "videojs"
    		}
    	}
    }
  ]
}
// **.js 使用
require('videojs');
複製代碼
  1. webpack.HotModuleReplacementPluginhot: true共同使用時,沒法熱更新。

QQ截圖20210528145936.png hot: true會自動添加webpack.HotModuleReplacementPlugin插件,無需再次添加配置。 7. speed-measure-webpack-plugin插件在 build 時,沒法使用。 8. webpack5 再也不爲 Node.js 提供自動引入polyfills。

根據錯誤提示修改便可。

  1. 生產環境中構建完成,可是未退出命令

    thread-loader插件在生產環境中,預熱 worker 池會致使此問題。

  2. 升級後,webpack 對代碼要求更加嚴格,須要按需修改。

參考

相關文章
相關標籤/搜索