如何有效提升快应用(Webpack)编译速度

背景

在开发快应用时,少不了构建操作: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

  1. 通过修改 quickapp.config.js 配置:
module.exports = {
  cli: {
    devtool: "none",
  },
};
  1. 通过命令行
// 此方法,在 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 的搜索时间(故此字段仅为介绍,无需增加配置)。所以如果代码中精确到完整文件名,在大工程多引用文件数的情况下,也是能节省一笔可观的时间消耗哟。

随着工具的升级,及开放自定义程度的提高,整体编译速度也会不断提升,敬请期待。

您可能会感兴趣的文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335