解读 minipack 源码
整体流程
- 同步读取入口文件,然后通过
babylon解析js文件,再通过babel-traverse来操作js的语法树,再交给babel-core转码成现在浏览器可以跑起来的代码,
- 其中通过一个数组来保存已经构建好父文件和子文件的依赖关系,
``js [ './message.js' ] [ './name.js' ] [] ``
- 然后不断去遍历这个存有依赖关系的数组,得出另外一个数组,这个数组包含文件的索引id,文件名,它的依赖文件,还有通过 `
babel-core` 转码出来的代码。
```js queue: [ { id: 0, filename: './example/entry.js', dependencies: [ './message.js' ], code: '"use strict";\n\nvar _message = require("./message.js");\n\nvar _message2 = _interopRequireDefault(_message);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nconsole.log(_message2.default);', mapping: { './message.js': 1 } }, { id: 1, filename: 'example/message.js', dependencies: [ './name.js' ], code: '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\n\nvar _name = require("./name.js");\n\nexports.default = "hello " + _name.name + "!";', mapping: { './name.js': 2 } }, { id: 2, filename: 'example/name.js', dependencies: [], code: '"use strict";\n\nObject.defineProperty(exports, "__esModule", {\n value: true\n});\nvar name = exports.name = \'world\';', mapping: {} } ]
```
- 最关键的是,通过遍历生成的
queue 数组,把 其中的code 属性值放进 CommomJs 模块规范的代码打包函数里。
``js function (require, module, exports) { // 写的代码,即上面的 queue 数组对象中的不同对象的code属性的值 }) ``
- 最后一步就是,让浏览器读取到第4步打包好的代码,这里没有引入其他插件,是通过内部的代码块实现的。
例子是下面的:
```js (function(modules) { function require(id) { const [fn, mapping] = modules[id];
function localRequire(name) { return require(mapping[name]); }
const module = { exports : {} };
fn(localRequire, module, module.exports);
return module.exports; } require(0); })({0: [function(){console.log('hhhhh')}]}) ```
真实的代码如下:
```js (function(modules) { function require(id) { const [fn, mapping] = modules[id];
function localRequire(name) { return require(mapping[name]); }
const module = { exports : {} };
fn(localRequire, module, module.exports);
return module.exports; }
require(0); })({0: [ function (require, module, exports) { "use strict";
var _message = require("./message.js");
var _message2 = _interopRequireDefault(_message);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
console.log(_message2.default); }, {"./message.js":1}, ],1: [ function (require, module, exports) { "use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var _name = require("./name.js");
exports.default = "hello " + _name.name + "!"; }, {"./name.js":2}, ],2: [ function (require, module, exports) { "use strict";
Object.defineProperty(exports, "__esModule", { value: true }); var name = exports.name = 'world'; }, {}, ],}) ```
总结来说
通过babel解析代码成ES5代码,通过构建文件依赖关系,使用 commomJs 模块化打包文件,使用浏览器能理解的代码实现引入打包文件。
---
原始 Issue:heycqing/blog#7