从最基本的开始
首先,让我们从一个简单的例子开始:
1 | src |
其中,各文件内容如下:
1 | // index.js |
打包出的结果经过简化后如下所示:
1 | // webpackBootstrap 启动函数 |
打包后的结果是一个自执行函数,其参数是一个数组,存储了各个模块,每个模块就是一个函数,其参数分别为
module
,exports
,__webpack_require__
,每个模块以数组下标作为模块的 id。自执行函数中定义了函数
__webpack_require__(moduleId)
, 该函数类似于 nodejs 中的 require,其参数为模块 id,该函数首先判断模块是否已加载到 installedModules 对象之中,如果是,则直接返回缓存的结果,否则就新创建一个模块对象,并执行模块对应的函数,最后返回模块导出的内容。自执行函数最后调用
__webpack_require__(__webpack_require__.s = 2)
并传入了入口模块的 id,这样整个应用就跑起来了。
模块异步加载
假设我们的入口模块代码如下:
1 | import('./page1').then(page => { |
打包后的结果:
bundle.js
1 | (function(modules) { // webpackBootstrap |
0.bundle.js
1 | webpackJsonp([0],{ |
bundle.js
中 modules[4] 模块中执行的__webpack_require__.e/* import() */(0).then(__webpack_require__.bind(null, 3)).then(...)
可以分解为两步:其中__webpack_require__.e/* import() */(0)
是异步加载 chunk,__webpack_require__.bind(null, 3)
为安装模块。__webpack_require__.e
主要功能是通过 dom 操作插入 script 标签来异步加载 chunk 对应的 js 文件,新建了一个 Promise 对象 promise,并将 [resolve, reject, promise] 存在 installedChunks 中。异步加载的 chunk 会执行
webpackJsonp
方法,该方法中会执行 installedChunks 中存放的 resolve 方法,从而通知 modules[4] 中的代码继续执行。
整个过程可以用下图来表示:
提取公共代码
1 | src |
有时候网站会由多个页面组成,每个页面都是一个独立的单页面应用,这些页面技术栈相同且包含相同的业务代码,如果每个页面的代码都将这些公共的部分包含进去,势必会造成:1) 相同的资源重复加载 2) 每个页面的体积太大
为了解决这个问题,可以将公共代码提取出来,具体到上面的例子,我们可能希望最终打包的结果像这样:
为了实现上述要求,可以使用 CommonsChunkPlugin:
1 | const path = require('path') |