事情缘由

近段时间在做基于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. python面向对象-1

    1.面向对象的思想优点 优点: 简化代码 ,构建公共模板 ,扩展性强 思想: 类作为模板 ,对象通过模板实例化对象 ,对象去做事 ,抽象将显示存在的事物使用代码体现 2.三大特性 封装(狭义) : 对 ...

  2. arcgis api for javascript 学习(七) 调用发布地图信息,并将地图属性信息输出到Excel表格---进阶版

    我们在arcgis api for javascript 学习(三)已经学习到了关于调用地图信息进行属性输出的问题,不过通过代码我们实现后会发现还是有一些小瑕疵的,比如我们只能单个数据属性的输出,如果 ...

  3. JS 参考手册

    JS 参考手册 JavaScript 对象 HTML DOM 对象

  4. 2019 DevOps 技术指南

    原文链接:https://hackernoon.com/the-2018-devops-roadmap-31588d8670cb 原文作者:javinpaul 翻译君:CODING 戴维奥普斯 写在前 ...

  5. Spring Boot与ActiveMQ整合

    Spring Boot与ActiveMQ整合 1使用内嵌服务 (1)在pom.xml中引入ActiveMQ起步依赖 <dependency> <groupId>org.spri ...

  6. vue项目、路由

    目录 Vue项目创建 pycharm配置并启动vue项目 vue项目目录结构分析 js原型补充 vue项目生命周期 页面组件 配置自定义全局样式 路由逻辑跳转 路由重定向 组件的生命周期钩子 路由传参 ...

  7. Centos8尝鲜

    Centos 8阿里云下载地址https://mirrors.aliyun.com/centos/8.0.1905/isos/x86_64/ Centos8的一些变化 网络服务: 在/etc/sysc ...

  8. centos7 配置阿里镜像

    1. 备份原来的yum源 cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak 2.设置aliyun的y ...

  9. qt 自定义控件窗口提升

  10. Java连载55-接口的作用、接口举例

    一.接口的作用 1.可以使项目分层,所有层都面向接口开发,开发效率提高了. 2.接口使代码和代码之间的耦合度降低,就像内存条和主板的关系,变得“可插拔”,可以随意切换. ​总结:接口和抽象类能够完成某 ...