Faster, Higher, Stronger
更快,更高,更强

webpack3项目缩包实践总结

Hybrid app由于开发、更新非常方便,所以应用到的地方非常多。一般大家都是通过http(s)://协议访问web页面,所以其实并不会去考虑每次版本迭代时改动到的文件数量。最近在公司做了两个项目的缩包优化,在我们的场景下,大部分web页面是以资源包的形式下载到用户本地后通过file://协议访问的,如果每次迭代都有很多文件发生了变化,用户可能就需要下载大量的数据(通常是以压缩包的形式下载到客户端本地),在网络一般的时候,这种体验是非常不好的,所以我们会比较关注大家不太关心的增量包大小。这也是本文相对于网上大部分缩包相关文章的区别之处(本文以webpack3构建的项目为例,但思路都是相通的,可以借鉴)。

先说增量是个什么概念。假设你的项目第一版一共有index.html 、app.js 、app.css 、logo.png 4个文件,现在准备发布第二版,包括以下文件:

  • index.html (与第一版内容不一致);
  • app.js (与第一版内容不一致);
  • app.css (与第一版内容一致);
  • logo.png (与第一版内容一致);
  • tel.png (新增文件);

这里,增量的大小就是由index.html 、app.js 和tel.png 贡献的。这里我们要减少增量大小的话,主要从两个方面去考虑:

  1. 减小单个文件的大小(如果每个改动的文件都很小,整体的增量的大小也会小);
  2. 减少改动的文件数量(如果有个文件很大,但是某次上线时这个文件并没有改动,那么它就可以避免它的增量)。

网上大家提得比较多的那些点就不在这里重复提及了,本文主要讲以下几点。

一、固定moduleId和chunkId

如果你看些webpack3的编译产物,你会发现很多js的开头部分的格式非常一致,大概类似下面这样:

webpackJsonp([74],{1020:function(e,t,r){"use strict";function a(e){//...

在上面这个例子中,74表示的就是chunkId,后面的1020表示的就是moduleId。这两个id很容易变化,有时候可能你只是新加了一个页面,就导致编译产物中大量的文件发生了变化,但是用diff工具仔细对比后发现很多文件的内容里除了这两个id发生了变化外其他内容完全一致。在我们的场景下,是不希望产生这种diff的,所以就需要找到方法来固定moduleId和chunkId。

固定moduleId的方法非常简单,直接使用webpack3提供的HashedModuleIdsPlugin插件即可,官方的介绍信息在这里:https://webpack.docschina.org/plugins/hashed-module-ids-plugin/,下面是使用示例:

// webpack配置文件
module.exports = {
    // ..
    plugins: [
        // ...
        new webpack.HashedModuleIdsPlugin(),
        // ...
    ].filter(Boolean),
}

固定chunkId没有官方的现成插件可以用,但是也非常简单,下面这么短短不到20行的代码就可以实现一个固定chunkId的插件了(用不容易变的chunk名代替容易变的chunkId,当然前提需要我们保证chunk的名字不能重复,使其仍旧像是id一样可以保证唯一性):

// 文件名:webpack-fixed-chunk-id-plugin.js
module.exports = class FixedChunkIdPlugin {
    constructor (options) {
        this.options = options || {}
    }

    apply (compiler) {
        compiler.plugin('compilation', (compilation) =>
            compilation.plugin('before-chunk-ids', (chunks) => {
                chunks.forEach((chunk) => {
                    if (!chunk.id) {
                        // 要求chunk名不重名
                        chunk.id = chunk.name
                    }
                })
            })
        )
    }
}

使用示例:

const FixedChunkIdPlugin = require('./webpack-fixed-chunk-id-plugin.js')

// webpack配置文件
module.exports = {
    // ..
    plugins: [
        // ...
        new FixedChunkIdPlugin(),
        // ...
    ].filter(Boolean),
}

在上面这两个插件的帮助下,我们重新编译一下产物,会发现开头的地方变成了类似下面这种样子:

webpackJsonp(["your-chunk-name"],{"your-module-id":function(e,a,t){"use strict";function r(e){// ...

二、将较大的公共文件拆成多个减少命中大小

我们可能会通过webpack.optimize.CommonsChunkPlugin插件将某些公共组件/文件抽取出来打包成单个文件,以便减小编译产物中的重复代码量。这一步输出的单个文件通常会比较大,其实我们可以继续进一步的优化,将这里涉及到的文件按目录、功能、文件名首字母(比如讲某个目录下的文件名以a-r开头的文件打包到一起,s-z开头的打包到一起)等我们觉得合适的方式分开输出,就可以避免每次有涉及到公共文件的改动就导致一个很大的增量的问题,因为按这种方式拆分后你的改动很可能只会命中其中个别的文件。我在拆文件时通常会尽量保持每个输出的最终文件大小在100~200k之间(我们的项目除了内置于APP中使用,同时也会被用于微信端,拆太小的话会导致wap站用户通过http(s)://协议访问页面时由于请求数过多影响页面加载速度)。

赞(0) 打赏
未经允许不得转载:峰间的云 » webpack3项目缩包实践总结

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏