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