为了更明实现一个webpack本文会使用fasterpack来代替webpack关键字
实现一个最简fasterpack
#!/usr/bin/env node
const path = require("path");
const fs = require("fs");
const config = require(path.resolve("./fasterpack.config.js"));
class Fasterpack {
constructor(config) {
//缓存配置
this.config = config;
//保存入口
this.entry = config.entry;
//获取执行根目录
this.root = process.cwd();
//创建 modules
this.modules = {};
}
/**
*
* @param {*} code 源码
* @param {*} parent 文件父目录
*/
pares(code, parent) {
// console.log("parent", parent);
const deps = [];
const r = /require\(['"](.*)['"]\)/g;
const r1 = /[\r\n]/g;
//替换 require
code = code.replace(r, function (match, arg) {
const retPath = path.join(parent, arg.replace(/'|"/g, ""));
// 添加 依赖路径
deps.push(retPath);
return `__fasterpack_require__("./${retPath}")`;
});
//替换换行
code = code.replace(r1, function (match, arg) {
return "\\n";
});
code = code.replace(/\"/g, '\\"');
code = `"${code}"`;
return { code, deps };
}
/**
*
* @param {*} modulePath 模块物理路径
* @param {*} name 项目中文件唯一路径 Key
*/
createModule(modulePath, name) {
const modulePathKeys = Object.keys(this.modules);
const fileContent = fs.readFileSync(modulePath, "utf-8");
//递归判断 是否已经注册
if (!modulePathKeys.includes(name)) {
//返回解析后的源码和源码中的依赖
const { code, deps } = this.pares(fileContent, path.dirname(name));
this.modules[name] = `function(module,exports,__fasterpack_require__){
eval(${code})
}`;
// 递归创建module
deps.forEach((dep) => {
this.createModule(path.join(this.root, dep), `./${dep}`);
});
}
}
generateModuleStr() {
let fnTemp = "";
Object.keys(this.modules).forEach((name) => {
fnTemp += `"${name}":${this.modules[name]},`;
});
return `{${fnTemp}}`;
}
generateFile() {
//参数注入模板
this.tempalate = getTempalate(this.generateModuleStr(), this.entry);
fs.writeFileSync(`./dist/main.js`, this.tempalate);
console.log("写入完毕");
}
start() {
console.log("开始解析");
const entryPath = path.resolve(this.root, this.entry);
//创建缓存 module
this.createModule(entryPath, this.entry);
//生成文件
this.generateFile();
}
}
const getTempalate = (__modules_content__, __entry__) => {
return `(function (modules) {
const installModules = {};
function __faster_require__(moduleId) {
//是否缓存
if (installModules[moduleId]) {
console.log(installModules, moduleId, installModules[moduleId].exports);
return installModules[moduleId].exports;
}
var module = (installModules[moduleId] = {
exports: {},
});
modules[moduleId].call(
module.exports,
module,
module.exports,
__faster_require__
);
return module.exports;
}
//入口
return __faster_require__("${__entry__}");
})(${__modules_content__});`;
};
const fasterpack = new Fasterpack(config);
fasterpack.start();
接下来我们借助babel来改造一下
需要了解:
#!/usr/bin/env node
const path = require("path");
const fs = require("fs");
// 将源码转成 ast 语法树
const parser = require("@babel/parser");
// 解析ast语法书
const traverse = require("@babel/traverse").default;
// 解析转换源码
const { transformFromAst } = require("@babel/core");
const config = require(path.resolve("./fasterpack.config.js"));
class Fasterpack {
constructor(config) {
//缓存配置
this.config = config;
//保存入口
this.entry = config.entry;
//获取执行根目录
this.root = process.cwd();
//创建 modules
this.modules = {};
}
pares(fileContent, parentDirname) {
const deps = [];
const ast = parser.parse(fileContent, {
sourceType: "module",
});
traverse(ast, {
ImportDeclaration({ node }) {
deps.push(path.join(parentDirname, node.source.value));
},
});
let { code } = transformFromAst(ast, null, {
//转换标准
presets: ["@babel/preset-env"],
});
const r = /require\(['"](.*)['"]\)/g;
code = code.replace(r, function (match, arg) {
const retPath = path.join(parentDirname, arg.replace(/'|"/g, ""));
// 添加 依赖路径
return `__fasterpack_require__("./${retPath}")`;
});
return { code, deps };
}
/**
*
* @param {*} modulePath 模块物理路径
* @param {*} name 项目中文件唯一路径 Key
*/
createModule(modulePath, name) {
const modulePathKeys = Object.keys(this.modules);
const fileContent = fs.readFileSync(modulePath, "utf-8");
//递归判断 是否已经注册
if (!modulePathKeys.includes(name)) {
//返回解析后的源码和源码中的依赖
const { code, deps } = this.pares(fileContent, path.dirname(name));
this.modules[name] = `function(module,exports,__fasterpack_require__){
eval(${JSON.stringify(code)})
}`;
// 递归创建module
deps.forEach((dep) => {
this.createModule(path.join(this.root, dep), `./${dep}`);
});
}
}
generateModuleStr() {
let fnTemp = "";
Object.keys(this.modules).forEach((name) => {
fnTemp += `"${name}":${this.modules[name]},`;
});
return `{${fnTemp}}`;
}
generateFile() {
//参数注入模板
this.tempalate = getTempalate(this.generateModuleStr(), this.entry);
fs.writeFileSync(`./dist/main.js`, this.tempalate);
console.log("写入完毕", this.m);
}
start() {
console.log("开始解析");
const entryPath = path.resolve(this.root, this.entry);
//创建缓存 module
this.createModule(entryPath, this.entry);
//生成文件
this.generateFile();
}
}
const getTempalate = (__modules_content__, __entry__) => {
return `(function (modules) {
const installModules = {};
function __faster_require__(moduleId) {
//是否缓存
if (installModules[moduleId]) {
console.log(installModules, moduleId, installModules[moduleId].exports);
return installModules[moduleId].exports;
}
var module = (installModules[moduleId] = {
exports: {},
});
modules[moduleId].call(
module.exports,
module,
module.exports,
__faster_require__
);
return module.exports;
}
//入口
return __faster_require__("${__entry__}");
})(${__modules_content__});`;
};
const fasterpack = new Fasterpack(config);
fasterpack.start();