Josh Hsu

我配置了webpack的設置,讓編譯的時間減少超過一半以上的時間

> webpack冷啟動要花55秒左右,熱啟動要花24秒左右

我配置了webpack的設置,讓編譯的時間減少超過一半以上的時間

最近公司內部的專案在開發熱起動時,花費的時間越來越久

專案 vue2 搭配 element-ui 然後還有許多大大小小的套件,這個專案主要是做報表系統,有 70+以上的頁面,

相對應的 component 也好幾百個,再配合上 webpack + babel 的編譯, 所以光是起 server 就花的將近 55 秒的時間

// Usage library && framework "vue": "2.6.10", "@vue/cli-service": "3.5.3", "element-ui": "2.13.0", "moment": "2.29.1",

最近專案需求剛好告一段落,所以開始著手研究相對應的優化

這邊專注的是 DX(Development Experience)優化,並不是頁面的優化

#我們先寫一個 webpack plugin 來看啟動時間要耗時多久

如此一來我們才能量化所需的時()間()

先創建一個 ConsolelogPlugin.js,放在 root folder

需要的 library

// ConsolelogPlugin.js const chalk = require('chalk') /* console 顏色 */ const slog = require('single-line-log') /* 單行 Print console */ class ConsolegPlugin { constructor(options) { this.options = options } apply(compiler) { /** * Monitor file change 記錄當前改動文件 */ compiler.hooks.watchRun.tap('ConsolePlugin', (watching) => { const changeFiles = watching.watchFileSystem.watcher.mtimes for (let file in changeFiles) { console.log(chalk.green('當前改動文件:' + file)) } }) /** * before a new compilation is created. * 開始 compilation 編譯 。 */ compiler.hooks.compile.tap('ConsolePlugin', () => { this.beginCompile() }) /** * Executed when the compilation has completed. * 一次 compilation 完成。 */ compiler.hooks.done.tap('ConsolePlugin', () => { this.timer && clearInterval(this.timer) const endTime = new Date().getTime() const time = (endTime - this.starTime) / 1000 console.log(chalk.yellow(' 編譯完成')) console.log(chalk.yellow('編譯用時:' + time + '秒')) }) } beginCompile() { const lineSlog = slog.stdout let text = '開始編譯:' /* 記錄開始時間 */ this.starTime = new Date().getTime() this.timer = setInterval(() => { text += '█' lineSlog(chalk.green(text)) }, 50) } } module.exports = ConsolegPlugin

已經能測量出所耗時的時間後,接下來進入主題

#利用 緩存 loader 的執行結果 + 利用多核心 CPU 的效能加速

#緩存 loader 的執行結果

webpack babel setting Source

我們可以加上 cacheDirectory 的選項來 cache 之前編譯過的檔案,減少 webpack 構建時 Babel 重新編譯過程

#利用多核心 CPU 的效能加速

接下來我們使用HappyPack搭配 babel-loader 的 cache 來加速

#Vue2 cli 版本(Webpack)

// vue.config.js // import .. from .. // import ... from ... const ConsolelogPlugin = require('./ConsolelogPlugin') const HappyPack = require('happypack'); const os = require('os') const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) module.exports = { // .... // ...... configureWebpack: { // .... plugins: [ new ConsolelogPlugin() ] chainWebpack(config) { // ... // 只想在 development 的環境執行 config.when(process.env.NODE_ENV === 'development', config => { config.plugin('happypack') .use(HappyPack) .tap(options => { options[0] = { id: 'babel', loaders: ['babel-loader?cacheDirectory=true'], // 开启缓存 threadPool: happyThreadPool } return options }) const hRule = config.module.rule('js') hRule.test(/\.js$/) .include.add(resolve('src')) .end() hRule.uses.clear() hRule.use('happypack/loader?id=babel') .loader('happypack/loader?id=babel') .end() }) } } }

#React (webpack 4.44.1)

// webpack.config.dev.js // ... const ConsolelogPlugin = require('./ConsolelogPlugin') const HappyPack = require('happypack'); const os = require('os') const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length }) module.exports = { module: { rules: [ // 原本 // { // test: /\.jsx?$/, // exclude: /node_modules/, // use: { // loader: "babel-loader", // options: { // presets: ["@babel/preset-react","@babel/preset-env"], // }, // } // }, //改為 { test: /\.js?$/, exclude: /node_modules/, use:['happypack/loader?id=babel'] } ] } // .... plugins: [ //.... , // .... , new HappyPack({ id:'babel', // 這邊對應上面use的id loaders:['babel-loader?cacheDirectory=true'], // cache babel編譯過的檔案 threadPool: happyThreadPool }), new ConsolelogPlugin() ] }

#結論

React Router

原本約 55 秒 改進後約 16 秒 只剩下原本不到 1/3 的時間

當然修改後儲存的編譯時間也有變快 但我這邊就不做記錄了

#Ref

See all posts