依赖解析

1
2
const detective = require("detective");
const requires = detective(source);

深度遍历寻找依赖,返回一个依赖数组

源码比较简单,主要由三个函数构成

createModuleObject()

1
2
3
4
5
6
7
8
9
10
11
function createModuleObject(filePath) {
const source = fs.readFileSync(filePath, "utf-8");
const requires = detective(source);
const id = ID++;
return {
id,
filePath,
source,
requires
};

从目录信息构造需要的模块信息,传入一个文件path路径,返回一个而文件模块对象ModuleObject

getModules()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getModules(entry) {
const rootModule = createModuleObject(entry);
const modules = [rootModule];
//遍历依赖,把所有引用文件变成模块对象
for (const module of modules) {
module.map = {};
module.requires.forEach(dependency => {
const basedir = path.dirname(module.filePath);
const dependencyPath = resolve(dependency, { basedir });
const dependencyObject = createModuleObject(dependencyPath);
module.map[dependency] = dependencyObject.id;
modules.push(dependencyObject);
});
}
return modules;
}

获取所有的模块信息,传入一个入口文件path路径,作为根路径,调用createModuleObject()生成模块对象,遍历根路径的依赖,可以把所有引用文件变成模块对象,返回一个所有文件对象模块的数组,根据ID来调用

pack()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function pack(modules) {
//暴露模块IP和依赖
const modulesSource = modules.map(module =>
`${module.id}:{
factory:(module , require) {
${module.source}
},
map:${JSON.stringify(module.map)}
}`).join();
//返回一个立即执行的函数
return `(modules => {
const require = id => {
const { factory, map } = modules[id]
const localRequire = name => require(map(name))
const module = { exports: {} }
factory(module, localRequire)
return module.exports
}
require(0)
})({ ${ modulesSource })`;
}

传入一个Modules[]数组,通过工厂方式构造一个require()函数,把文件模块的ID和依赖暴露出来,方便require的调用,最后调用require(0),调用跟模块,返回一个立即执行的函数

用法

1
2
3
4
---npm install---
const pack = require("../bundle");
const fileWebpack = pack(path);