事情缘由

近段时间在做基于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. Java EE 基本开发流程及数据库连接池 Druid

    一. 公司开发基本流程    a. 了解需求信息(比较模糊)        需求,不是别人告诉你的,是你自己挖掘出来的.        售前工程师(对行业知识了解):编程学不好,但懂点代码,对人的综合 ...

  2. [转]UIpath advanced certification dumps

    本文转自:https://dotnetbasic.com/2019/06/uipath-advanced-certification-dumps.html UiPath advanced certif ...

  3. [Go] 轻量服务器框架基础TCP连接的抽象和封装

    对tcp连接部分以及与连接绑定的业务部分进行抽象和封装 主要是对连接的开启关闭和读写进行封装,抽象出接口,使用回调进行具体业务的绑定 zinterface/iconnection.go package ...

  4. Error:Cannot build artifact 'ssm:war exploded' because it is included into a circular dependency (artifact 'ssm:war exploded', artifact 'apinb-master:war exploded')

    打开 File->Project Structure –> Artifacts(ctrl+alt+shift+s) ,这里会有4个,我已经删除了,把 ssm:war 和 ssm:war e ...

  5. 新手学Html之JSP基础语法——入门(二)

    JSP基础语法 JSP注释 comment.jsp <%@ page language="java" contentType="text/html; charset ...

  6. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  7. ReactNative: 使用输入框TextInput组件

    一.简介 一个应用程序中,输入框基本不可或缺,它衍生的搜索功能在很多APP中随处可见.在iOS开发中,使用的输入框组件是UITextView和UITextField,在React-Native中使用的 ...

  8. 添加商品到购物车add_to_cart.php(学生笔记)

    <?php session_start();//启动session $goods_id = $_POST['goods_id'];//获取商品id $number = $_POST['num'] ...

  9. flex三个对齐属性的记忆方式

    今天在群里聊天有人说 flex的那几个居中属性好难记,时不时都要尝试一下,或者查看一下文档,现在我把我自己的记忆方式分享一下... 1. flex的居中主要是通过这三个属性来实现的: justify- ...

  10. echarts背景颜色渐变的三种类型

    // 线性渐变,多用于折线柱形图,前四个参数分别是 x0, y0, x2, y2, 范围从 0 - 1,相当于在图形包围盒中的百分比,如果 globalCoord 为 `true`,则该四个值是绝对的 ...