事情缘由

近段时间在做基于scratch3.0的改造项目。基于scratch-gui改造,项目本身已经很大了,然后里面还要用到scratch-blocks,scratch-vm,scratch-render等外部第三方项目。官方的配置是所有的东西打入一个lib中,所有的html都使用这一个lib。

现在有一个需求是:h5页面仅仅展示scratch做出来的作品,但是目前加载很慢,需要优化。

scratch原生的打包配置如下(html-webapck-plugin@3.2.0)

打包结果全部js在lib.min中,有26M左右

优化思路

第一阶段(不更改代码,仅仅做分包的优化):

  • 利用webpack optimization.splitChunks的vendors配置将所有的第三方包提取到vendors中【本人额外配置了一个所有入口都使用的第三方包bundle:‘vender.min'】;
  • 利用webpack optimization.splitChunks的default配置【默认的配置】自动提取各个入口js的共用代码组成bundle的功能。
  • 分离出manifest文件,确保没有更改的包打包结果不会更改。

上面基本都利用了默认的配置【不配置的属性即使用默认值】,webpack默认的配置【每一个版本还不太一样,比如最近的maxAsyncRequests已经是6了,maxInitialRequests为4】如下

module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};

优化配置如下,

打包结果如下:chunks中

其中vendors*.js 和 blocksonly~compatibilitytesting~gui~player.js即是默认的vendors和default配置提取出来的bundle。

是小了一点,但是项目还是太大了,特别是vendor.min.js。查看包发现工程引用的第三方模块中用到很多相同的模块

解决办法:使用别名

resolve: {
symlinks: false,
extensions: ['.js', '.jsx', '.json'],
alias: {
// 别名,防止node_modules多个地方引入同样的包会打多份
'scratch-l10n': path.resolve(__dirname, './node_modules/scratch-l10n'),
'scratch-blocks': path.resolve(__dirname, './node_modules/scratch-blocks'),
'scratch-render': path.resolve(__dirname, './node_modules/scratch-render'),
'scratch-svg-renderer': path.resolve(__dirname, './node_modules/scratch-svg-renderer'),
'scratch-audio': path.resolve(__dirname, './node_modules/scratch-audio'),
'immutable': path.resolve(__dirname, './node_modules/immutable')
}
},

打包后结果

小了3M。到目前为止,如果不更改代码基本已经无法再压缩了。

第二阶段:更改代码,一切与展示作品无关的东西都剥离后打包

  • 修改maxInitialRequests为4
  • 配置了公用vendors,优先提取大模块(默认情况是不用更改的,本人的项目比较特殊,原因看后面的描述)
  • player代码和gui的代码分开,去掉player中不必要的代码引入

这一阶段player的代码进行精简,不和blocksonly / compatibilitytesting / gui公用一套代码。项目后面加上了一些hash.

由于项目中需要对scratch-blocks做更改,将scratch-blocks作为项目的git子模块。

不配置vendors则和默认配置等同,等同于如下代码

vendors配置如下:

为什么要自定义配置vendors?这和配置maxInitialRequests也有很大关系。

按照webpack默认的default和vendors配置会自动提取公用代码生成新bundle,其中有两个参数对这个提取影响比较大:maxAsyncRequests和maxInitialRequests。意思是,webpack会提取各个入口中的相同代码组成一个个被至少两个入口使用的bundle,比如下面

chunks/vendors~blocksonly~compatibilitytesting~gui.302b4bd4e64a213f38f4.js 表示是vendors提取出来给blocksonly | compatibilitytesting | gui 这三个入口公用的

chunks/vendors~blocksonly~compatibilitytesting~gui~player.aa28b51afdced7c4a928.js  表示是vendors提取出来给blocksonly | compatibilitytesting | gui | player 这四个入口公用的

如果不限制,则vendors~*.js这样的组合会很多。一个player.html初始化加载时需要请求很多js。所以maxAsyncRequests和maxInitialRequests限制了这个请求数,让打包后提取公共代码js时保证每一个入口异步请求和初始化请求的js数量控制在设定的值。这样就会出现某些多个入口使用的公用代码不能被单独提取出来的情况。

由于默认的初始化js请求数量限制为3,本人更改为4(当然也可以更大,本人这块不想有跟多js请求,这块根据各自的项目而定)

然后本人想把一写体积比较大的(比如scratch-blocks)块在有maxInitialRequests限制的情况下优先提取出来,其他的就打入各自的包。就直接更改了vendors

没有配置vendors和配置了vendors的对比(后面的就是配置了vendors)

没有配置vendors,子模块scratch-blocks在多处打包,没有被提取出来。修改vendors,去掉了只匹配“node_moddules”;只要三个以上chunks用到的模块都提取到vendors。

配置vendors打包后的结果可以看到,在网页端访问player页面,只需要引入三个js

vendor.min.938f6588ea10bb385ceb.js    7844K

vendors~blocksonly~compatibilitytesting~gui~player.b694ee6564cf5e22ed72.js   2998K

player.cb540c9b28aafd8d9503.js   95K

一共就10M多一点,比起之前要加载26M要好很多了。

这里面有一个点需要注意:

按照webpack默认的default和vendors配置会自动提取公用代码生成新bundle,然后自动被html-webpack-plugin配置的html引用。但是,3.X的html-webpack-plugin如果不指定chunk,且在HtmlWebpackPlugin中显式配置chunk的名称,则不起作用。

比如:

上面的vendors~blocksonly~***.js文件生成了,但是没有被引入到index.html代码中,导致访问index.html缺少这个文件直接展示不出来。

3.x的配置例子如下

一旦指定splitChunks.name的名称,那么所有的入口必然引用这个bundle,无法生成各自入口的个性化bundle。所以建议升级html-webpack-plugin到4

后记:

====================================

2019.12.20 笔记写的时候是19年6月左右。现在"vendor"的配置名称改成了“lib.min”,毕竟vendors是第三方包的意思。html-webpack-plugin 4.x也不用再配置中指定“vendor.min”,只需要配置入口chunks就行,插件会自动查找入口chunk被提取出的公共代码的路径。

优化要点:

1.代码压缩/图片压缩

2.公用代码提取,稳定资源最好提取到单独的包(比如node_modules中的包)

3.非相关代码拆分

4.tree shaking的使用。这块难点比较大,特别是用babel处理的时候。

5. chunkhash和contenthash合理使用

纯属个人经验,有错误请大家多指正!

webpack打包优化实践的更多相关文章

  1. Webpack 打包优化之速度篇

    在前文 Webpack 打包优化之体积篇中,对如何减小 Webpack 打包体积,做了些探讨:当然,那些法子对于打包速度的提升,也是大有裨益.然而,打包速度之于开发体验和及时构建,相当重要:所以有必要 ...

  2. Webpack 打包优化之体积篇

    谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发展也是如火如荼,百家争鸣:从早期的王者Browserify, Grunt,到后来赢得宝 ...

  3. [转] Webpack 打包优化之体积篇

    谈及如今欣欣向荣的前端圈,不仅有各类框架百花齐放,如Vue, React, Angular等等,就打包工具而言,发展也是如火如荼,百家争鸣:从早期的王者Browserify, Grunt,到后来赢得宝 ...

  4. 记一次webpack打包优化

    未进行打包优化的痛点: 随着项目的不断扩大,引入的第三方库会越来越多,我们每次build的时候会对所有的文件进行打包,耗时必定很长,不利于日常开发. 解决思路: 第三方库我们只是引入到项目里来,一般不 ...

  5. webpack打包优化之外部扩展externals的实际应用

    目录 前言 externals定义 用法 string array object function regex 实际案例 打包时间 打包之后包的大小 浏览器加载 需要注意 参考 前言 使用vue-cl ...

  6. webpack打包优化并开启gzip

    应用场景:项目使用webpack2.x进行打包,打包后静态资源通过nginx转发配置: 问题:webpack打包后的资源文件特别,特别大,没打包之前页面一个页面js有2M左右(其中已经抽离了css)? ...

  7. 基于CommonsChunkPlugin,webpack打包优化

    前段时间一直在基于webpack进行前端资源包的瘦身.在项目中基于路由进行代码分离,http://www.cnblogs.com/legu/p/7251562.html.但是打包的文件还是很大,特别是 ...

  8. webpack 打包优化的四种方法(多进程打包,多进程压缩,资源 CDN,动态 polyfill)

    如今,webpack 毫无疑问是前端构建领域里最耀眼的一颗星,无论你前端走哪条路线,都需要有很强的webpack 知识.webpack 的基本用法这里就不展开讲了.主要探讨一下如何提高 webpack ...

  9. webpack打包优化点

    目录 1. noParse 2. 包含和排除目录 3. IgnorePlugin 4. happypack 5. DllPlugin动态链接库 6. 热更新 7. 开发环境 tree-shaking ...

随机推荐

  1. 使用脚本进行ansible批量主机的免密配置

    应用场景: 在应用ansible的实际情况中,有一个很现实的问题,ansible是需要对主机做ssh免密登陆的,而挨个对主机做免密是非常的繁琐的,挨个敲IP不仅非常的繁琐而且容易出错,为解决这个问题, ...

  2. pip安装插件报错。

    报错: Cannot unpack file C:\Windows\TEMP\pip-unpack-4mbfczpj\simple (downloaded from C:\Windows\TEMP\p ...

  3. [CrackMe]160个CrackMe之015

    吾爱破解专题汇总:[反汇编练习]160个CrackME索引目录1~160建议收藏备用 一.破解 该破解比较简单,其是一个静态密码  2G83G35Hs2 ,输入进去即可破解. 1)栈定位法找到用户代码 ...

  4. js 对 只包含简单类型数据的对象 为元素 组成的数组 进行去重

    /** * 对于由简单类型数据组成的对象为元素组成的数组进行去重操作 * @params {Array} 需要去重的对象数组 * @returns {Array} 去重后的对象数组 */ functi ...

  5. Java - 包装类 常量池

    概述: 在Java中存在一些基本数据类型,这些基本数据类型变量,不能像其他对象一样调用方法,属性.... 一些情况下带来一些问题,包装类就是为了解决这个问题而出现 包装类可以使得这些基础数据类型,拥有 ...

  6. 使用NodeJS模块-第三方提供的模块(什么是npm)

    第三方开发者提供的模块 第三方模块是由NodeJS社区或第三方个人开发的功能模块,这些功能模块以软件包的形式存在.被发布在npmjs注册表中.npmjs是一个注册中心,所有软件包的信息都会被记录到该注 ...

  7. GPS NMEA-0183协议常用报文数据格式

    点击上方↑↑↑蓝字[协议分析与还原]关注我们 " 整理的GPS有关的协议分析资料." 之前分析一些车载设备的流量时,有部分经验,在这里和大家分享. 产生这些流量的设备通常是实体终端 ...

  8. ios中设置UIButton圆角,添加边框

    //例如: UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = CGRectMake(50, ...

  9. opencv-python 图像基础处理(二)

    图像阈值 ret, dst = cv2.threshold(src, thresh, maxval, type) - src: 输入图,只能输入单通道图像,通常来说为灰度图- dst: 输出图- th ...

  10. 记录Android开发中遇到的坑

    1. 出现错误提示:Intel HAXM is required to run this AVD,VT-x is disabled in BIOS的解决办法. 点击SDK图标,安装Intel x86 ...