背景
在開發(fā)快應(yīng)用時,少不了構(gòu)建操作:npm run build(官方 IDE 集成了這些操作,本質(zhì)上也是調(diào)用同樣方法)。這是因?yàn)榭鞈?yīng)用有自己的 DSL 語法,直接寫出來,在底層不能識別,需要把業(yè)務(wù)代碼編譯成底層能運(yùn)行的代碼(感興趣的同學(xué),可在 build 文件夾查看編譯后的代碼產(chǎn)物)。整個過程就跟 Vue 和 React 工程的打包一樣。等待的過程總是漫長,當(dāng)項(xiàng)目越來越大的時候,難免還要花上點(diǎn)時間??烧l不希望這個過程越快越好呢?本篇就在于探討,如何有效提升快應(yīng)用(Webpack)編譯速度。
快應(yīng)用工程是基于 hap-toolkit 編譯打包的。而它的功能,部分是基于 Webpack 開發(fā)。所以下面跟大家分享的,關(guān)于提升快應(yīng)用編譯速度的方法,同樣也適用于基于 Webpack 構(gòu)建的 Web 應(yīng)用。
本文原本首發(fā)于 vivo 快應(yīng)用官方博客。
基于插件
不過畢竟是 Webpack 上的封裝,所以不是所有方法都可以用上?,F(xiàn)在 hap-toolkit 支持一些自定義配置了,可以使用部分 loader 和 plugin。詳情請查看 ToolKit 項(xiàng)目配置 里面有自定義 webpack plugin 的代碼示例。我們這里要講的就是使用 hard-source-webpack-plugin 插件來為編譯加速。
對于做過 Webpack 性能優(yōu)化的同學(xué),可能有用到過 HardSourceWebpackPlugin 插件,用于為模塊提供中間緩存步驟。它能明顯提升第二次構(gòu)建速度:
HardSourceWebpackPluginis a plugin for webpack to provide an intermediate caching step for modules. In order to see results, you'll need to run webpack twice with this plugin: the first build will take the normal amount of time. The second build will be significantly faster.
安裝
yarn add --dev hard-source-webpack-plugin
// OR
npm i hard-source-webpack-plugin --save-dev
使用
在項(xiàng)目根目錄下增加 quickapp.config.js 文件,做如下代碼配置:
const HardSourceWebpackPlugin = require("hard-source-webpack-plugin");
module.exports = {
webpack: {
plugins: [new HardSourceWebpackPlugin()],
},
};
如上,一點(diǎn)簡單的配置,即可輕松使用。當(dāng)然,也可以通過添加參數(shù),來“量身”定制。下面拿快應(yīng)用官方 Sample 來看一下。
參數(shù)介紹
首先,完全的第一次編譯,會花費(fèi)較長時間。這是因?yàn)榫幾g過程需要依賴到 babel 模塊,在 webpack 里它化身為 babel-loader,編譯過程需要解析成 AST,再轉(zhuǎn)換成我們要的輸出格式(對該部分知識感興趣的同學(xué)可自行查閱)。這一過程極為耗時,所以作為一個有擔(dān)當(dāng)?shù)囊蕾?,它也?yīng)該有自己的緩存。
這一配置已經(jīng)在 hap-toolkit 寫好了。可以在項(xiàng)目目錄下node_modules/.cache/babel-loader看到 babel 緩存。
使用 hard-source-webpack-plugin 插件,編譯速度會有顯著提高。
在上述存放緩存的地點(diǎn),可以發(fā)現(xiàn)多了個 hard-source 的文件夾,里面正是存放著插件生成的緩存。再看看一些參數(shù)的介紹,我們直接在代碼上以注釋的形式展示:
new HardSourceWebpackPlugin({
// 緩存存放的地址,以 webpack 的執(zhí)行目錄加該字段拼接而成,一般都是存放于項(xiàng)目目錄下
// 也可以寫成絕對路徑,存放到別的地方
cacheDirectory: "node_modules/.cache/hard-source/[confighash]",
// 緩存文件夾的名字生成方式,這里的值對于上方的 configHash
configHash: function (webpackConfig) {
return require("node-object-hash")({ sort: false }).hash(webpackConfig);
},
// 環(huán)境hash,其實(shí)就是監(jiān)聽依賴有沒有更改,有的話也更新緩存
// 一般 files 填一個 package-lock.json 也夠了
environmentHash: {
root: process.cwd(),
directories: [],
files: ["package-lock.json", "yarn.lock"],
},
cachePrune: {
// 緩存的存在時間,默認(rèn)為兩天
maxAge: 2 * 24 * 60 * 60 * 1000,
// 緩存的最大容量,默認(rèn)為 50 MB
sizeThreshold: 50 * 1024 * 1024,
},
});
需要注意下,如果用官方 IDE 來打開項(xiàng)目,由于 IDE 的運(yùn)行路徑,與項(xiàng)目路徑不一致,會導(dǎo)致報錯,需要設(shè)置 environmentHash 來修正:
new HardSourceWebpackPlugin({
environmentHash: {
root: __dirname,
},
});
基于文件操作
一 移除 source-map
source-map,簡而言之,就是編譯后的代碼與源代碼的一個映射。在進(jìn)行代碼調(diào)試時候,執(zhí)行環(huán)境運(yùn)行的是編譯后的代碼,但可以看到對應(yīng)的源代碼;最常見的就是瀏覽器中,通過打斷點(diǎn),定位到源代碼去,這樣就可以發(fā)現(xiàn)源代碼出現(xiàn)的問題。
通過閱讀 Webpack Devtool 文檔,可以知道,source-map 構(gòu)建也需要時間;且跟還原度也有關(guān)系,越精確越耗時間,尤其是值為 source-map 模式。
在 hap-toolkit 默認(rèn)設(shè)置,release 就是設(shè)置為 “none”;debug 模式由于要考慮到還原度,選擇了 “cheap-eval-source-map”。那么,如果平時無需 source-map,可以直接將其設(shè)置為 “none”,即可進(jìn)一步加快速度。同時,也會帶來問題,即調(diào)試之時,無法精確對應(yīng)源代碼。您可以有兩種方式,來關(guān)閉 source-map:
- 通過修改
quickapp.config.js配置:
module.exports = {
cli: {
devtool: "none",
},
};
- 通過命令行
// 此方法,在 IDE 中不適用
npm run build -- --devtool none
這個對于速度有小幅提升。這個雖然效果不如緩存提升得那么明顯,但是勝在作用于每次打包,對于首次打包也是有效的。
二 減少編譯代碼
我們知道,編譯速度跟代碼量也有關(guān)系,那么減少“需要編譯的文件”,當(dāng)然就可以加快速度。開發(fā)時候,通常都是一個或者幾個相關(guān)頁面來開發(fā)。所以開發(fā)過程中可以只編譯當(dāng)前需要的頁面。
hap-toolkit 收集頁面是通過 manifest.json 的 router.page 配置,而不是通過工程的 src 下具體文件。所以可以先去掉不相干的頁面配置,而不需要去除實(shí)際文件。
最簡單情況可以只留下單個頁面,對比起好幾個甚至十幾個頁面的編譯速度,提速效果還是相當(dāng)明顯的。
三 加快文件搜索
代碼量對編譯速度有影響,自然的,尋找需要編譯的文件也要花時間的。
我們在代碼中對文件的引用,寫了很多相對路徑,而且也習(xí)慣不寫文件后綴。webpack 沒有那么神可以洞察開發(fā)者內(nèi)心的訴求,而是根據(jù)配置好的搜索條件,不斷地循環(huán)查找。
webpack 的 resolve 配置就是干這個活的。
我們摘取其中實(shí)用的來說,先上代碼,在快應(yīng)用中 quickapp.config.js 配置:
const path = require("path");
module.exports = {
webpack: {
resolve: {
alias: {
"@src": path.resolve(__dirname, "src"),
},
modules: ["./src/components"],
},
},
};
1、resolve.modules:配置 Webpack 去哪些目錄下尋找第三方模塊,默認(rèn)配置是去 node_modules 目錄下尋找。
有時做了一個公用組件庫,給不同的地方調(diào)用。在不同地方的引入,就有可能導(dǎo)致這個路徑會很長,如 import '../../../components/button'。這時可以利用 modules 配置項(xiàng)優(yōu)化,假如組件庫在 ./src/components 目錄下,就可以給 modules 增加'./src/components'這樣一個地址,供 webpack 快速命中資源位置。
2、resolve.alias: 給路徑起別名。當(dāng)代碼中使用了眾多相對路徑,不僅我們?nèi)フ疫@個文件費(fèi)勁,webpack 也是需要時間去解析。所以直接配置好絕對路徑,在代碼中用別名代替冗長的路徑。于編譯解析,于代碼書寫,都是利好,兩開花!
3、resolve.extensions: 則是告知 webpack 獲取哪些類型的文件。比如:['js', 'ux'],當(dāng)我們引用文件是這樣寫 import util from './util',在定位到目錄之后,就開始按照 util.js -> util.ux 的順序去尋找該文件。
也就是這個字段配置作用是方便了代碼的書寫,但是增加 webpack 的搜索時間(故此字段僅為介紹,無需增加配置)。所以如果代碼中精確到完整文件名,在大工程多引用文件數(shù)的情況下,也是能節(jié)省一筆可觀的時間消耗喲。
隨著工具的升級,及開放自定義程度的提高,整體編譯速度也會不斷提升,敬請期待。