前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >webpack4.0各个击破(4)—— Javascript & splitChunk

webpack4.0各个击破(4)—— Javascript & splitChunk

作者头像
大史不说话
发布于 2018-09-10 07:46:46
发布于 2018-09-10 07:46:46
81600
代码可运行
举报
运行总次数:0
代码可运行

webpack作为前端最火的构建工具,是前端自动化工具链最重要的部分,使用门槛较高。本系列是笔者自己的学习记录,比较基础,希望通过问题 + 解决方式的模式,以前端构建中遇到的具体需求为出发点,学习webpack工具中相应的处理办法。(本篇中的参数配置及使用方式均基于webpack4.0版本本篇摘要: 本篇主要介绍基于webpack4.0splitChunks分包技术。

一. Js模块化开发

javascript之所以需要打包合并,是因为模块化开发的存在。开发阶段我们需要将js文件分开写在很多零碎的文件中,方便调试和修改,但如果就这样上线,那首页的http请求数量将直接爆炸。同一个项目,别人2-3个请求就拿到了需要的文件,而你的可能需要20-30个,结果就不用多说了。

但是合并脚本可不是“把所有的碎片文件都拷贝到一个js文件里”这样就能解决的,不仅要解决命名空间冲突的问题,还需要兼容不同的模块化方案,更别提根据模块之间复杂的依赖关系来手动确定模块的加载顺序了,所以利用自动化工具来将开发阶段的js脚本碎片进行合并和优化是非常有必要的。

二. Js文件的一般打包需求

  • 代码编译(TSES6代码的编译)
  • 脚本合并
  • 公共模块识别
  • 代码分割
  • 代码压缩混淆

三. 使用webpack处理js文件

3.1 使用babel转换ES6+语法

babelES6语法的转换工具,对babel不了解的读者可以先阅读《大前端的自动化工厂(3)——Babel》一文进行了解,babelwebpack结合使用的方法也在其中做了介绍,此处仅提供基本配置:

webpack.config.js:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...  
module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
             loader: 'babel-loader'
          }
        ]
      }
    ]
  },
 ...

.babelrc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
{
    "presets":[
        ["env",{
            "targets":{
                "browsers":"last 2 versions"
            }
        }
        ]],
    "plugins": [
         "babel-plugin-transform-runtime" 
    ]
}

3.2 脚本合并

使用webpack对脚本进行合并是非常方便的,毕竟模块管理文件合并这两个功能是webpack最初设计的主要用途,直到涉及到分包和懒加载的话题时才会变得复杂。webpack使用起来很方便,是因为实现了对各种不同模块规范的兼容处理,对前端开发者来说,理解这种兼容性实现的方式比学习如何配置webpack更为重要。webpack默认支持的是CommonJs规范,但同时为了扩展其使用场景,webpack在后续的版本迭代中也加入了对ES harmony等其他规范定义模块的兼容处理,具体的处理方式将在下一章《webpack4.0各个击破(5)—— Module篇》详细分析。

3.3 公共模块识别

webpack的输出的文件中可以看到如下的部分:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/******/    function __webpack_require__(moduleId) {
/******/
/******/        // Check if module is in cache
/******/        if(installedModules[moduleId]) {
/******/            return installedModules[moduleId].exports;
/******/        }
/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {}
/******/        };
/******/
/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/        // Flag the module as loaded
/******/        module.l = true;
/******/
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }

上面的__webpack_require__( )方法就是webpack的模块加载器,很容易看出其中对于已加载的模块是有统一的installedModules对象来管理的,这样就避免了模块重复加载的问题。而公共模块一般也需要从bundle.js文件中提取出来,这涉及到下一节的“代码分割”的内容。

3.4 代码分割

1. 为什么要进行代码分割?

代码分割最基本的任务是分离出第三方依赖库,因为第三方库的内容可能很久都不会变动,所以用来标记变化的摘要哈希contentHash也很久不变,这也就意味着我们可以利用本地缓存来避免没有必要的重复打包,并利用浏览器缓存避免冗余的客户端加载。另外当项目发布新版本时,如果第三方依赖的contentHash没有变化,就可以使用客户端原来的缓存文件(通用的做法一般是给静态资源请求设置一个很大的max-age),提升访问速度。另外一些场景中,代码分割也可以提供对脚本在整个加载周期内的加载时机的控制能力。

2. 代码分割的使用场景

举个很常见的例子,比如你在做一个数据可视化类型的网站,引用到了百度的Echarts作为第三方库来渲染图表,如果你将自己的代码和Echarts打包在一起生成一个main.bundle.js文件,这样的结果就是在一个网速欠佳的环境下打开你的网站时,用户可能需要面对很长时间的白屏,你很快就会想到将Echarts从主文件中剥离出来,让体积较小的主文件先在界面上渲染出一些动画或是提示信息,然后再去加载Echarts,而分离出的Echarts也可以从速度更快的CDN节点获取,如果加载某个体积庞大的库,你也可以选择使用懒加载的方案,将脚本的下载时机延迟到用户真正使用对应的功能之前。这就是一种人工的代码分割。

从上面的例子整个的生命周期来看,我们将原本一次就可以加载完的脚本拆分为了两次,这无疑会加重服务端的性能开销,毕竟建立TCP连接是一种开销很大的操作,但这样做却可以换来对渲染节奏的控制和用户体验的提升异步模块懒加载模块从宏观上来讲实际上都属于代码分割的范畴。code splitting最极端的状况其实就是拆分成打包前的原貌,也就是源码直接上线

3. 代码分割的本质

代码分割的本质,就是在“源码直接上线”“打包为唯一的脚本main.bundle.js”这两种极端方案之间寻找一种更符合实际场景的中间状态,用可接受的服务器性能压力增加来换取更好的用户体验。

4. 配置代码分割

code-splitting技术的配置和使用方法将在下一小节详细描述。

5. 更细致的代码分割

感兴趣的读者可以参考来自google开发者社区的文章《Reduce JavaScript Payloads with Code Splitting》自行研究。

3.5 代码混淆压缩

webpack4中已经内置了UglifyJs插件,当打包模式参数mode设置为production时就会自动开启,当然这不是唯一的选择,babel的插件中也能提供代码压缩的处理,具体的效果和原理笔者尚未深究,感兴趣的读者可以自行研究。

四. 细说splitChunks技术

4.1 参数说明

webpack4废弃了CommonsChunkPlugin插件,使用optimization.splitChunksoptimization.runtimeChunk来代替,原因可以参考《webpack4:连奏中的进化》一文。关于runtimeChunk参数,有的文章说是提取出入口chunk中的runtime部分,形成一个单独的文件,由于这部分不常变化,可以利用缓存。google开发者社区的博文是这样描述的:

The runtimeChunk option is also specified to move webpack's runtime into the vendors chunk to avoid duplication of it in our app code.

splitChunks中默认的代码自动分割要求是下面这样的:

  • node_modules中的模块或其他被重复引用的模块 就是说如果引用的模块来自node_modules,那么只要它被引用,那么满足其他条件时就可以进行自动分割。否则该模块需要被重复引用才继续判断其他条件。(对应的就是下文配置选项中的minChunks为1或2的场景)
  • 分离前模块最小体积下限(默认30k,可修改) 30k是官方给出的默认数值,它是可以修改的,上一节中已经讲过,每一次分包对应的都是服务端的性能开销的增加,所以必须要考虑分包的性价比。
  • 对于异步模块,生成的公共模块文件不能超出5个(可修改) 触发了懒加载模块的下载时,并发请求不能超过5个,对于稍微了解过服务端技术的开发者来说,【高并发】压力测试这样的关键词应该不会陌生。
  • 对于入口模块,抽离出的公共模块文件不能超出3个(可修改) 也就是说一个入口文件的最大并行请求默认不得超过3个,原因同上。

4.2 参数配置

splitChunks的在webpack4.0以上版本中的用法是下面这样的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async',//默认只作用于异步模块,为`all`时对所有模块生效,`initial`对同步模块有效
      minSize: 30000,//合并前模块文件的体积
      minChunks: 1,//最少被引用次数
      maxAsyncRequests: 5,
      maxInitialRequests: 3,
      automaticNameDelimiter: '~',//自动命名连接符
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          minChunks:1,//敲黑板
          priority: -10//优先级更高
        },
        default: {
          test: /[\\/]src[\\/]js[\\/]/
          minChunks: 2,//一般为非第三方公共模块
          priority: -20,
          reuseExistingChunk: true
        }
      },
      runtimeChunk:{
          name:'manifest'
      }
    }
  }

4.3 代码分割实例

注:实例中使用的demo及配置文件已放在附件中。

  • 单页面应用 单页面应用只有一个入口文件,splitChunks的主要作用是将引用的第三方库拆分出来。从下面的分包结果就可以看出,node_modules中的第三方引用被分离了出来,放在了vendors-main.[hash].js中。
  • 多页面应用 多页面应用的情形稍显复杂,以《webpack4:连奏中的进化》一文中的例子进行代码分割处理,源码的依赖关系为: entryA.js: vue vuex component10k entryB.js: vue axios component10k entryC.js: vue vuex axios component10k 经过代码分割后得到的包如下图所示:

splitChunks提供了更精确的分割策略,但是似乎无法直接通过html-webpack-plugin配置参数来动态解决分割后代码的注入问题,因为分包名称是不确定的。这个场景在使用chunks:'async'默认配置时是不存在的,因为异步模块的引用代码是不需要以<script>标签的形式注入html文件的。

chunks配置项设置为allinitial时,就会有问题,例如上面示例中,通过在html-webpack-plugin中配置excludeChunks可以去除pageabout这两个chunk,但是却无法提前排除vendors-about-page这个chunk,因为打包前无法知道是否会生成这样一个chunk。这个场景笔者并没有找到现成的解决方案,对此场景有需求的读者也许可以通过使用html-webpack-plugin事件扩展来处理此类场景,也可以使用折中方案,就是第一次打包后记录下新生成的chunk名称,按需填写至html-webpack-pluginchunks配置项里。

### 4.4 结果分析

通过Bundle Buddy分析工具或webpack-bundle-analyser插件就可以看到分包前后对于公共代码的抽取带来的影响(图片来自参考文献的博文):

五. 参考及附件说明

【1】附加中文件说明:

  • webpack.spa.config.js——单页面应用代码分割配置实例
  • main.js——单页面应用入口文件
  • webpack.multi.config.js——多页面应用代码分割配置实例
  • entryA.js,entryB.js,entryC.js——多页面应用的3个入口

【2】参考文献: 《Reduce JavaScript Payloads with Code Splitting》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-08-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
webpack4 新特性
wepack4 出来已经有半年了,目前最新的 release 版本为 4.19.0。由于之前项目打包一直存在性能问题,所以我一直很关注 webpack 和其社区的发展。目前来说 webpack4 已经趋于稳定,很多关键的插件也都更新了对 webpack4 的支持;更为重要的是,webpack4 的官方文档(中英文)已经很完善了,因此现在不学习 webpack4,更待何时。根据 webpack 作者 Tobias Koppers 的说法,他们已经着手开始开发 webpack5 了。
李振
2021/11/26
1.3K0
webpack4 新特性
webpack4:连奏中的进化
webpack4在2月底的时候发布,这次webpack4有了一个名字"Legato",也就是"连奏"的意思,寓意webpack在不断进化,而且是无缝(no-gaps)的进化。webpack的进化点是通过捐赠者和用户投票来决定的,之前在介绍webpack3的时候,曾给出过投票数在前几名的优化点,集中在用户体验、构建性能(速度和产出大小)、通用和适配性(es module、typescript、web assemble)等。webpack4发布了,下面将结合文档和实践,验证一下webpack是否兑现了当初的诺
用户1217459
2018/05/29
1.4K0
Webpack的异步加载原理及分包策略(深度好文,建议收藏)
webpack ensure 有人称它为异步加载,也有人称为代码切割,他其实就是将 js 模块给独立导出一个.js 文件,然后使用这个模块的时候,再创建一个 script 对象,加入到 document.head 对象中,浏览器会自动帮我们发起请求,去请求这个 js 文件,然后写个回调函数,让请求到的 js 文件做一些业务操作。
winty
2020/12/07
4.8K0
Webpack的异步加载原理及分包策略(深度好文,建议收藏)
webpack性能优化(2):splitChunks用法详解
之前写的《webpack性能优化(0):webpack性能优化概况-优化构建速度》、《webpack性能优化(1):分隔/分包/异步加载+组件与路由懒加载》
周陆军博客
2023/03/18
1.8K0
从webpack4打包文件说起
一堆的webpack配置教程看腻了?这里有webpack4的打包及加载机制,要不了解一下?而这一切就得从打包文件说起。
elson
2018/08/01
3K1
刚刚,发布Webpack中级教程系列
- 对于浏览器而言,html文件是用户访问的入口点,也是所有资源的挂载点,所有资源都是通过html中的标记来进行引用的。
达达前端
2021/08/18
8990
刚刚,发布Webpack中级教程系列
Webpack 性能系列四:分包优化
默认情况下,Webpack 会将所有代码构建成一个单独的包,这在小型项目通常不会有明显的性能问题,但伴随着项目的推进,包体积逐步增长可能会导致应用的响应耗时越来越长。归根结底这种将所有资源打包成一个文件的方式存在两个弊端:
Tecvan
2021/12/09
4.9K0
Webpack 性能系列四:分包优化
webpack4.x常用配置
yarn init -y yarn add webpack webpack-cli -D
FinGet
2020/01/13
2K0
webpack4.x常用配置
由浅至深了解webpack异步加载背后的原理
1、module:我们源码目录中的每一个文件,在 webpack 中当作module来处理(webpack 原生不支持的文件类型,则通过 loader 来实现)。module组成了chunk。
ACK
2020/02/08
1.7K0
由浅至深了解webpack异步加载背后的原理
webpack配置完全指南
对于入门选手来讲,webpack 配置项很多很重,如何快速配置一个可用于线上环境的 webpack 就是一件值得思考的事情。其实熟悉 webpack 之后会发现很简单,基础的配置可以分为以下几个方面: entry 、 output 、 mode 、 resolve 、 module 、 optimization 、 plugin 、 source map 、 performance 等,本文就来重点分析下这些部分。
gogo2027
2022/09/26
3.2K0
webpack务虚扫盲
打包工具的角色 所谓打包工具在web开发中主要解决的问题是: (1)文件依赖管理。毕竟现在都是模块化开发,打包工具首先就是要梳理文件之间的依赖关系。 (2)资源加载管理。web本质就是html、js和
用户1217459
2018/01/31
1.2K0
webpack务虚扫盲
前端-手摸手,带你用合理的姿势使用webpack4(下)
webpack 4 最大的改动就是废除了 CommonsChunkPlugin 引入了 optimization.splitChunks。
grain先森
2019/03/29
1.3K0
前端-手摸手,带你用合理的姿势使用webpack4(下)
webpack 学习笔记系列06-打包优化
可选值:async(默认) | initial | all(推荐),针对下面的 a.js 和 b.js
CS逍遥剑仙
2021/06/27
2K0
webpack4:多页面及分离第三方库和公用文件配置
本篇开始学习webpack打包的构建配置,所用版本为webpack 4.16.1和webpack-cli 3.2.3。
前端_AWhile
2019/08/29
2.8K0
webpack生产、开发公共配置拆分
代码已上传至github github代码地址:https://github.com/Miofly/mio.git
用户10106350
2022/10/28
6030
小白入门级!webpack基础、分包大揭秘
导语 | 若你对webpack仅仅是处于使用阶段,觉得webpack原理太杂太乱太多,但是觉得大概了解下webpack的大致原理也不错。亦或是想要了解分包优化如何进行配置呢?以及为什么webpack官方分包配置会从 CommmonsChunkPlugin演变成SplitChunksPlugin呢?我按照自己的方式,通过查阅、整理相关文档,梳理一些比较容易让大家纠结的点,让大家通过本篇文章,大概了解webpack是干了什么? 一、webpack前生今世 (一)前端石器时代----->工业化时代 前端变迁转折
腾讯云开发者
2022/06/16
1.6K0
小白入门级!webpack基础、分包大揭秘
webpack深入浅出实战系列
https://github.com/luoxue-victor/learn_webpack/
前端迷
2020/02/19
1.7K0
webpack深入浅出实战系列
浅入webpack4 高效简单的配置
在vue-cli3中已经将webpack等详细配置(config)去除,我们配置webpack只能在vue.config.js里进行配置,这里我个人总结了一套webpack的优化方案模板并且附有我个人的讲解(尚在研究中)。 总体优化这几个方面:
饼干_
2022/08/07
1.1K0
浅入webpack4 高效简单的配置
webpack实战——代码分片
对于web应用来说通常会有一些库和工具是不常变动的,可以将它们放在一个单独的入口中,由该入口产生的资源不会经常更新,因此可以有效地利用客户端缓存,让用户不必在每次请求页面时都让资源重新加载。
流眸
2020/09/03
9020
webpack 构建之 splitChunks 优化与 manifest
1 背景 相信对于每个刚接触构建的同学来说, webpack 都是难以跨越的一道坎,它凭着抽象的概念、“言简意赅” 的文档,难倒了一众英雄好汉。 由于自己平时从零手写 webpack 配置的机会比较少,所以对 webpack 里的一些配置不都是特别清楚。 最近的一个需求需要给页面资源增加 md5 版本号,我正好借着这个机会,把项目里的 webpack 配置都重新梳理了一遍。 本文对于基本的配置概念(如 entry 、 output 等)就不一一赘述了,着重介绍的是 splitChunks 和 manifes
用户1097444
2022/06/29
2.6K0
webpack 构建之 splitChunks 优化与 manifest
相关推荐
webpack4 新特性
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验