这段时间在琢磨自己手写一个构建工具,不过在这之前,我们先试着梳理一下webpack的理念,毕竟它山之石可以攻玉,有助于我们想好该如何设计自己的项目。
简介
Webpack is a static module bundler for modern JavaScript applications.
这是关于webpack的介绍,本质上,他就是一个打包器。将js模块打包成一个或者多个。实现如下代码里的能力:
a.js + b.js + c.js. => bundle.js
打包器出现的原因,在此不多讲,网上有很多文章都讲过了。接下来我们讲一讲webpack把多个js文件打包成一个bundle文件的核心思路是什么。
从构建产物反推核心流程
Webpack 是一个庞大的体系,如果从源码的角度,分析从头到尾的流程,那么就会过于复杂,也没必要。毕竟我们学习的主要是核心设计理念。
那么,我们可以试着从结果反推过程,从打包后的代码来分析,webpack的思路。
在 mode: ‘none’, devtool: ‘cheap-source-map’,的配置下,我们可以看到打包出来的代码大概长这个样子:
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["Magotan"] = factory();
else
root["Magotan"] = factory();
})(window, function(){
return (function(modules){
// xxxx
})([
//xxxx
])['default']
})
显而易见的是这是一个IIFE,简化一下,在加上具体的实现代码,就成了下面这样:
(function webpackUniversalModuleDefinition() {
exports["Magotan"] = (function (modules) {
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
return __webpack_require__(0);
})([
/* 0 */ //模块数组列表 数组下标即为模块id
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["default"] = ({
getInstance: function getInstance() {
if (magotan === null) {
throw new Error('未初始化实例,请先通过config初始化');
}
return magotan;
},
}),
/* 1 */
(function (module, exports, __webpack_require__) {
var toObject = __webpack_require__(2);
var $keys = __webpack_require__(4);
__webpack_require__(21)('keys', function () {
return function keys(it) {
return $keys(toObject(it));
};
});
}),
// ...
});
])['default'];
})()
通过上面的代码我们可以看出,我们将项目中所有使用到的模块的代码以及依赖关系存在一个modules的数组中,然后通过 webpack自定义的require方法,从入口文件,即id = 0 的模块为起点,递归执行模块。
至此我们可以分析得出,webpack核心流程就是两步
- reslove modules阶段 递归解析 产出 Dependency graphs
Bundle 阶段 将上个阶段的产物,组装成数组并用函数包裹,从入口文件开始递归执行
后续
在理清楚了webpack的设计思路之后,更多的就是具体实现上的问题,比如如何拿到模块之间的关系(利用AST),如何保证不出现循环引用(利用installedModules 对象) 等等,更多的内容会在后续文档中有介绍。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。