You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(function(modules){varparentJsonpFunction=window["webpackJsonp"];window["webpackJsonp"]=functionwebpackJsonpCallback(chunkIds,moreModules,executeModules){varmoduleId,chunkId,i=0,resolves=[],result;for(moduleIdinmoreModules){if(Object.prototype.hasOwnProperty.call(moreModules,moduleId)){modules[moduleId]=moreModules[moduleId];}}if(executeModules){for(i=0;i<executeModules.length;i++){result=__webpack_require__(executeModules[i]);}}returnresult;};varinstalledModules={};// The require functionfunction__webpack_require__(moduleId){if(installedModules[moduleId]){returninstalledModules[moduleId].exports;}// Create a new module (and put it into the cache)varmodule=installedModules[moduleId]={i: moduleId,l: false,exports: {}};// Execute the module functionmodules[moduleId].call(module.exports,module,module.exports,__webpack_require__);// Flag the module as loadedmodule.l=true;// Return the exports of the modulereturnmodule.exports;}})([]);
关于webpack的公共代码提取和运行
CommonsChunkPlugin
基本配置
name
: 名称,等同于
options.async
或者options.children
被设置,所有的 chunk 都会被使用,否则options.filename
会用于作为 chunk 名。chunks
: 通过 chunk name 去选择 chunks 的来源。chunk 必须是公共chunk 的子模块。如果被忽略,所有的入口chunk (entry chunk) 都会被选择。理解
vue-cli
webpack默认配置中对于CommonsChunkPlugin
的配置:分步理解:
第一步:提取公共包
第二步:提取公共包映射关系
manifest: webpack打包默认模块,通过 manifest,webpack 能够对「你的模块映射到输出 bundle 的过程」保持追踪。
HashedModuleIdsPlugin
固定模块id为了便于看出效果,我们可以尝试将
vue
和其他node包分开打包,使用配置如下:在
main.js
中对依赖包jquery
分别进行移除操作,未添加HashedModuleIdsPlugin
:添加了
HashedModuleIdsPlugin
因为未添加
HashedModuleIdsPlugin
时,模块id是根据webpack的解析顺序增量的,如果变换解析顺序,那模块id也会随之改变,所以需要使用HashedModuleIdsPlugin
,它是根据模块相对路径生成模块标识,如果模块没有改变,那模块标识也不会改变。async
属性处理,异步加载时提取公共代码:当我们使用异步加载代码时,而且
test1
和test2
同时使用了第三方包,如jquery
如下:此时,如果没有使用
async
属性,打包结果如下:使用
async
属性,打包结果如下:-------------------------------------------------这是分割线--------------------------------------------------
Webpack4之SplitChunksPlugin
webpack官网:
现有CommonsChunkPlugin的问题:CommonsChunkPlugin的思路是基于父子关系的,使得其只能统一抽取到父chunk,造成父chunk过大,不可避免的存在重复引入,引入多余代码。
例如:我们打包多页面时候:
其中
main.js
引入了vue
和jquery
,而main4.js
只引入了vue
,打包后的结果:打包后,
vender
包含了vue
和jquery
,也就是说当我们在加载pageb的时候,多加载不需要的jquery
代码。SplitChunksPlugin的思路:
引入
chunkGroup
的概念,在入口chunk
和异步chunk
中发现被重复使用的模块,将重复模块以vendor-chunk
的形式分离出来,也就是vendor-chunk
可能有多个,不再受限于所有chunk中都共同存在的模块。升级了webpack4之后,production模式下,SplitChunksPlugin插件是默认被启用的,默认配置如下:
也就是说,默认情况下,webpack会根据下述条件自动进行代码块分割:
关于
SplitChunksPlugin
不再做多的介绍,有需要可以查看没有了CommonsChunkPlugin,咱拿什么来分包(译)打包后文件分析
为了方便查看,我们用最简单的配置去打包,以下为打包配置:
一般情况
从 main.js 开始看代码
可以看到,打包后 js 文件的加载顺序是先
manifest.js
,之后才是main.js
,这里先看看 main.js 的内容:删去一些无关代码,首先关注到的是
webpackJsonp
这个函数,可以看见是不在任何命名空间下的,也就是manifest.js
应该定义了一个挂在window
下的全局函数main.js
往这个函数传入三个参数并调用。这里先记住两个点:
exports
的函数__webpack_exports__
和一个类似require
的函数__webpack_require__
,这两个应该是模块化的关键。带着以上疑问,我们去看
manifest.js
manifest.js 代码阅读
manifest.js
内部是一个IIFE
。这个函数会接受一个空数组作为参数,该数组被命名为 modules。果然在 window 上挂了一个名为webpackJsonp
的函数。它接受的三个参数,分别名为chunkIds
,moreModules
,executeModules
。对应了 main.js 中调用webpackJsonp
时传入的三个参数。看下
webpackJsonp
:webpackJsonp 先是for
遍历了一次moreModules
,将moreModules
内的所有方法都存在modules
, 也就是自执行函数执行时传入的数组。然后判断
executeModules
, 也就是第三个参数是否存在,如存在即执行__webpack_require__
方法。installedModules 是一个缓存的容器,如果缓存中有对应的 moduleId,那么直接返回它的 exports,不然就定义并赋值一个吧。
__webpack_require__
最后的返回值是module.exports
。webpack 就是将每一个 js 文件封装成一个函数,每个文件中的 require 方法对应的就是
__webpack_require__
,__webpack_require__
会根据传入的 moduleId 再去加载对应的代码。以上面的例子总结,梳理一下打包后代码执行的流程:
manifest.js
,在里面定义了一个webpackJsonp
方法;main.js
:执行webpackJsonp
函数,将所有的 moreModules, 也就是每一个依赖的文件存起来。eitI
作为参数去执行__webpack_require__
,__webpack_require__
执行了eitI
值定义的方法,这个方法中有以I6/Z
作为参数去执行__webpack_require__
(可以理解为加载了依赖文件test2.js
),将依赖文件导出的值作为__webpack_require_
函数返回值后供eitI
内使用。eitI
值定义的方法没有导出值,__webpack_require__
返回空对象,然后webpackJsonp
方法执行完毕。总结:
首先
manifest.js
会定义一个webpackJsonp
方法,待其他打包后的文件(也可称为 chunk)调用。当调用 chunk 时,会先将该 chunk 中所有的 moreModules, 也就是每一个依赖的文件也可称为 module存起来。
之后通过
executeModules
判断这个文件是不是入口文件,决定是否执行第一次__webpack_require__
。而__webpack_require__
的作用,就是根据这个 module 所 require 的东西,不断递归调用__webpack_require__
,__webpack_require_
函数返回值后供 require 使用。当然,模块是不会重复加载的,因为
installedModules
记录着 module 调用后的 exports 的值,只要命中缓存,就返回对应的值而不会再次调用 module。webpack 打包后的文件,就是通过一个个函数隔离 module 的作用域,以达到不互相污染的目的。异步加载
这里是demo的代码:
从上面代码看出,
test4
是懒加载的,只有在点击了按钮才会加载这部分js代码,看一下打包后的运行效果:可以看出浏览器一开始只加载了
main.js
和manifest.js
,在点击按钮后,才加载了05d9040b8834b81d1aeb6.js
。说明代码是被分割了的,只要当对应的条件触发时,浏览器才会去加载指定的资源。而无论之后我们点击多少次,05d9040b8834b81d1aeb6.js
文件都不会重复加载。所以这里先留下一个问题:如何做到不重复加载?从 main.js 开始看代码
和上文的一般情况相比,问我们注意到
__webpack_require__.e
这个方法,传入一个数值之后返回一个promise
。这方法当promise
决议成功后执行切换文本的逻辑,失败则执行__webpack_require__.oe
。综上,我们希望在
manifest.js
找到这三个问题的答案:__webpack_require__.e
方法的逻辑__webpack_require__.oe
方法的逻辑manifest.js 代码阅读
部分截取
__webpack_require__.e
代码:总的来说,就是该方法中接受一个名为 chunkId 的参数,返回一个 promise,解释见注释,按数字顺序阅读。
__webpack_require__.oe
方法流程:当异步请求文件发起时,先判断该 chunk 是否已被加载,是的话直接返回一个成功的 promise,让 then 执行的函数 require 对应的 module 即可。不然则构造一个 script 标签加载对应的 chunk,下载成功后挂载该 chunk 内所有的 module。下载失败则打印错误。
【参考】
CommonsChunkPlugin
知多一点 webpack 的 CommonsChunkPlugin
webpack增量打包
详解CommonsChunkPlugin的配置和用法
简单易懂的 webpack 打包后 JS 的运行过程
简单易懂的 webpack 打包后 JS 的运行过程(二)
webpack CommonsChunkPlugin 和 SplitChunksPlugin 思路
Webpack4之SplitChunksPlugin
The text was updated successfully, but these errors were encountered: