用實驗的思路優化webpack4項目編譯速度

最近開發的時候遇到一個問題:當項目愈來愈大的時候,webpack構建和編譯的速度變得很慢。儘管webpack4官方宣稱速度提升了90%以上,但實際使用的時候感受速度和webpack2也差很少。我實在受不了熱加載的時候要等幾秒才能編譯好,因而就開始了優化之路。
最終優化的效果不錯,提速達到了80%以上。一路上按着之前作實驗的思惟去優化,經歷了各類問題,相比於分享解決問題的方法,我反而更想分享下解決問題的思路。html

先量化目標

通常作實驗以前,咱們都要先定一個目標。
可是問題來了,雖然感受很慢,但我不知道具體花了多少時間,慢是慢在哪裏,因此也沒辦法知道咱們能夠優化到什麼程度,優化也無從下手了。 因而首要的任務就是得到webpack編譯過程的信息。
在webpack的官方文檔中找了一大圈後,發現了配置中devServer.stats屬性能夠得到編譯過程的完整信息node

stats: {
    timings: true,
    modules: false,
    assets: false,
    entrypoints: false,
    assetsSort: 'field',
    builtAt: false,
    cached: false,
    cachedAssets: false,
    children: false,
    chunks: false,
    chunkGroups: false,
    chunkModules: false,
    chunkOrigins: false,
    performance: true,
    errors: true,
    warnings: true,
},
複製代碼

配成這樣以後獲得了構建和編譯的時間:webpack

能夠看到構建時間是40s,改動代碼後編譯的時間是5.4s。
既然webpack4宣稱能夠提速90%,那目前的狀況確定是有某些地方配置不當,咱們就先定個目標,將編譯時間優化到1s如下。

猜想可能影響速度的因素

目前的項目是多入口的項目,每一個入口之間沒有太多的關聯,可是卻放在了一塊兒打包和編譯。咱們平時開發的時候若是每次只編譯一個入口的文件會不會快一點呢?
本來有三個入口,只加載一個入口的時候能夠看到:git

構建和編譯的速度都加快了。變成了30s和3.4s。
既然有效,就寫幾個命令來方便開發不一樣的入口:

"scripts": {
    "dev": "webpack-dev-server --config ./webpack.config/dev.js --hot --inline",
    "teacher": "app=teacher webpack-dev-server --config ./webpack.config/dev.js --hot --inline",
    "student": "app=student webpack-dev-server --config ./webpack.config/dev.js --hot --inline",
    "home": "app=home webpack-dev-server --config ./webpack.config/dev.js --hot --inline",
    }
複製代碼

在package.json中dev命令前加了一個app=XXX的參數github

const teacherEntry = {
    ueditor: [
        'babel-polyfill',
        './src/common/UEditor/ueditor.config.js',
        './src/common/UEditor/ueditor.all.js',
        './src/common/UEditor/kityformula-plugin/addKityFormulaDialog.js',
        './src/common/UEditor/kityformula-plugin/getKfContent.js',
        './src/common/UEditor/kityformula-plugin/defaultFilterFix.js'
    ],
    teacher: ['./src/app/teacher/index.js'],
    teacherLogin: './src/app/teacherLogin/js/teacherLogin.js'
};
const studentEntry = {
    student: ['babel-polyfill', './src/app/student/index.js'],
    studentLogin: './src/app/studentLogin/js/studentLogin.js'
};
const homeEntry = {
    home: './src/app/home/index.js'
};
const entryObj = {
    teacher: teacherEntry,
    student: studentEntry,
    home: homeEntry
};

const entry = process.env.app
    ? entryObj[process.env.app]
    : Object.assign({}, teacherEntry, studentEntry, homeEntry);
複製代碼

而後在webpack.base.config.js中加上了根據process.env.app的值來加載不一樣入口的代碼,這樣就實現開發時跑不一樣的命令加載不一樣入口的效果了。web

檢查webpack config中是否有影響性能的配置

接下來就用控制變量的方法去逐個去掉webpack的loader和plugin,而後觀察減小的時間了。json

new WriteFilePlugin({
    test: /^((?!hot-update).)*$/
}),
複製代碼

發現用到了一個寫入文件的插件,將全部文件都寫到出口了,但實際上只須要寫入html文件就好了,因而改爲緩存

new WriteFilePlugin({
    test: /\.html$/,
    useHashIndex: true
}),
複製代碼

改後構建和編譯時間變成了30s和3s,有了一點點優化。
而後發現babel編譯js的時候沒有忽略掉node_modules目錄。bash

{
    test: /\.js$/,
    include: /(src|node_modules\/flv.js)/,
    exclude: /(node_modules)/,
    loader: 'babel-loader'
},
複製代碼

加上後發現時間變成了27s和2.2s,已是一開始的一半了。babel

對比別人的項目看有沒有能夠借鑑的地方

配置看得差很少了,沒有再發現有問題的地方了,因而開始google查找別人的優化方法。
後來找到了一個相似的項目用了happypack(多線程編譯)和cache-loader(緩存),感受優化效果還不錯:

new HappyPack({
    id: 'babel', // 對於loaders id
    loaders: ['cache-loader', 'babel-loader?cacheDirectory'], // 是用babel-loader解析
    threadPool: happyThreadPool,
    verboseWhenProfiling: true // 顯示信息
}),
複製代碼

加上了happypack和cache-loader以後能夠看到第一次構建速度有了很大的提高,減小到了13.5s!
可是編譯的速度基本沒什麼變化,仍是2s。革命還沒有成功,同志仍需努力啊。

觀察編譯過程的信息,尋找優化點

要進一步優化編譯的速度,只好去分析編譯的過程到底發生了什麼問題了。
將stats中的assets設置爲true,觀察編譯的文件:

發現每個js文件都有一個相同大小的.map文件,這樣豈不是會花費一倍的時間!?因而趕忙谷歌查一下.map文件是何方神聖。 後來發現它來自於webpack配置中的devtool,主要用於調試程序,官方配置說明以下:

原來項目中一直是用了最慢的source-map!因而趕忙修改配置:

devtool: 'cheap-module-eval-source-map'
複製代碼

改完後試了一下,構建和編譯時間縮短爲11s和0.8s。

終於將編譯速度降到了1s一下,完成了最初定下的目標。

總結

通過這一路的優化以後,深感webpack的配置博大精深。每一個項目可能都有不一樣的問題影響着webpack的速度,因此在此分享定位問題的思路,但願能幫助遇到相似問題的朋友一步步找到問題,提升速度。

Author: Brady

相關文章
相關標籤/搜索