webpack源码分析之二:code-splitting

2018-05-26 admin

前言

code-splitting是webpack最引人瞩目的特性之一,此特性将代码分离到不同的bundle文件中。详细介绍官网code-split,这次实现则在笔者上次文件打包之上做开发。

功能分析

官网上有三种方式实现

  1. 入口起点:使用 entry 选项手动分离代码。
  2. 防止重复:使用 CommonsChunkPlugin 去重和分离 chunk。
  3. 动态导入:通过模块的内联函数调用来分离代码。

1本质则是多个入口的chunk,2则在以common.js为入口文件,将多入口的chunk切分为按切割文件,通过jsonp加载。在这里笔者则介绍最为复杂的3的实现,

对于webpack 的切割文件的引入本质就是jsonp,动态引入一个约定好格式的js,并运行。

__webpack_require__.e = function requireEnsure(chunkId) {
....
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.src = __webpack_require__.p + "" + chunkId + ".bundle.js";
    head.appendChild(script);
....
}

切割文件去除注释如下

webpackJsonp([1],[function(){},function(){}])

而在入口文件的webpackJsonpCallback函数内,则是将切割的文件包含的modules依次放入存储在modules内

function webpackJsonpCallback(chunkIds, moreModules){
....
for(moduleId in moreModules) {
             if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
                 modules[moduleId] = moreModules[moduleId];
             }
         }
}     
....    

所以实现以上功能需求如下:

  1. 定位切割点并组装异步加载的文件所需要的依赖的parse模块
  2. 生成各个chunk的所包含的module模块chunks模块
  3. 根据chunks,通过文件流写入文件的writeChunks模块

例子

require('d');

function a() {
    require.ensure(['./a'], function () {
        require('c');
    });
}

require.ensure(['./b'], function () {
    require('./m');
});

require('./e');

实现

parse模块

实现思路:

  1. 通过递归,以及文件树的特征定位到require.ensure
  2. 将arguments第一个参数的数组,第二个参数的函数内递归搜索require,存入数组asyncs内,并递归下去

数据结构如下:

{
    filename: '/Users/zhujian/Documents/workspace/webpack/simple-webpack/example/main.js',
    id: 0,
    requires: [{
            name: 'd',
            range: [8, 11],
            id: 1
        }],
    rangeRequires: [[0, 7]],
    asyncs: [{
            requires: [{
                    name: './a',
                    id: 2
                }, {
                    name: 'c',
                    range: [88, 91],
                    id: 3
                }],
            asyncs: [],
            rangeRequires: [80, 87],
            ensureRequires: [34, 58]
        },
        {
            requires: [{
                    name: './b',
                    id: 4
                }, {
                    name: './m',
                    range: [156, 161],
                    id: 5
                }],
            asyncs: [],
            rangeRequires: [148, 155],
            ensureRequires: [106, 130]
        }],
}

chunks模块

由于各个依赖文件的源码都包含在modlues内,所以chunks包含的是具体各个切割文件所包需module的moduleId。

实现思路:

  1. 通过入口mainPath 找到modules的入口mainModule
  2. 将mainModule 的requires遍历,将值归入本chunk的modules内,将asyncs遍历,依次新建chunk,并关联父chunk,以上两个依次递归遍历。
  3. 最终生成完了之后,将各个非根节点的chunk遍历,将依赖的modules遍历对比父节点的chunk,如有重复标记’in-parent’

数据结构如下

{ '0': 
   { id: 0,
     modules: { '0': 'include', '1': 'include', '2': 'include' } },
  '1': 
   { id: 1,
     modules: 
      { '1': 'in-parent',
        '3': 'include',
        '4': 'include',
        '5': 'include',
        '6': 'include' },
     parentId: 0 },
  '2': 
   { id: 2,
     modules: { '5': 'include', '6': 'include' },
     parentId: 0 
     }
}

writeChunks模块

实现思路:

  1. 如果chunks的个数超过1,入口chunk则加载包含webpackJsonp,webpack_require.e等支持jsonp函数的模版,未超过则加载简单的仅包含__webpack_require__的模版
  2. 加载非入口chunk则头部加载webpackJsonp,以及标示chunkid
  3. webpackJsonp的入参有两种,一种数组,一种以moduleId为key的对象。为数组时候则需要将以[,modlue]等方式保证顺序

如:

clipboard.png

代码实现

本人的简易版webpack实现simple-webpack

(完)

[转载]原文链接:https://segmentfault.com/a/1190000015041164

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-33061.html

文章标题:webpack源码分析之二:code-splitting

相关文章
JavaScript正则进阶之路——活学妙用奇淫正则表达式
有些童鞋肯定有所疑惑,花了大量时间学习正则表达式,却发现没有用武之地,正则不就是验证个邮箱嘛,其他地方基本用不上,其实,大部分人都是这种感觉,所以有些人干脆不学,觉得又难又没多大用处。殊不知,想要成为编程大牛,正则表达式必须玩转,GitH...
2017-05-31
Webpack(含 4)配置详解——从 0 配置一套开发模板
前言 源代码 熟悉 webpack 与 webpack4 配置。 webpack4 相对于 3 的最主要的区别是所谓的零配置,但是为了满足我们的项目需求还是要自己进行配置,不过我们可以使用一些 webpack 的预设值。同时 webpack...
2018-05-02
为你的 VS Code 搭建远程开发环境
开篇先说一下自己遇到的烦恼,介绍下写这篇文章的背景。我有一台低配的 MacBook 和 一台性能强悍的台式机。之前自己都是在 Mac 上跑前端项目的,那台台式机基本上处于闲置状态,偶尔用来看看文档。后来随着自己需要做服务端开发,有时候需要同...
2018-02-26
ajax教程之ajax使用Http请求
ajax中是如何让使用http请求的呢? 在传统的JS编程中,如果您希望从服务器上的文件或数据库中得到任何的信息,或者向服务器发送信息的话,就必须利用一个 HTML 表单向服务器 GET 或 POST 数据。而用户则需要单击“提交”按钮来发...
2015-11-12
VSCode配置react开发环境的步骤
vscode 默认配置对于 react 的 JSX 语法不友好,体现在使用自动格式化或者粘贴后默认缩进错误,尽管可以通过改变 language mode 缓解错误,但更改 language mode 后的格式化依然不够理想。 通过搭配使用 ...
2017-12-28
bootstrap table之通用方法( 时间控件,导出,动态下拉框, 表单验证 ,选中与获取信息)代码分享
1.bootstrap-table 单击单行选中 $('#gzrwTable').on('click-row.bs.table', function(e, row, $element) { $(&#x...
2017-02-17
JS教程之基础
javascript教程之什么是 JavaScript? JavaScript 被设计用来向 HTML 页面添加交互行为。JavaScript 是一种脚本语言(脚本语言是一种轻量级的编程语言)。JavaScript 由数行可执行计算机代码组...
2015-11-12
DOM之通俗易懂讲解
DOM 是所有前端开发每天打交道的东西,但是随着 jQuery 等库的出现,大大简化了 DOM 操作,导致大家慢慢的 “遗忘” 了它的本来面貌。不过,要想深入学习前端知识,对 DOM 的了解是不可或缺的,所以本文力图系统的讲解下 DOM 的...
2016-01-13
Ajax教程之Ajax介绍
Ajax 由 HTML、JavaScript™ 技术、DHTML 和 DOM 组成,这一杰出的方法可以将笨拙的 Web 界面转化成交互性的 Ajax 应用程序。本文的作者是一位 Ajax 专家,他演示了这些技术如何协同工作 —— 从总体概述...
2015-11-12
HTML 5 <em> <strong> <dfn> <code>
&lt;em&gt; 把文本定义为强调的内容。 &lt;strong&gt; 把文本定义为语气更强的强调的内容。 &lt;dfn&gt; 定义一个定义项目。 &lt;code&gt; 定义计算机代码文本。 &lt;samp&gt; 定义样本...
2015-11-12
回到顶部