手写webpack核心
通过入口文件获取每个文件的依赖(import),路径,代码。然后合并到一个js文件中。
完整代码
import fs from "fs";
import { resolve } from "path";
import { parse } from "@babel/parser";
import traverse from "@babel/traverse";
import ejs from "ejs";
import { transformFromAst } from "babel-core";
//1.读取文件
function getFileInfo(file) {
//打包文件路径 写死的 "./asset"
const source = fs.readFileSync(resolve("./asset", file), {
encoding: "utf-8"
});
//2.获取依赖 ast语法树 引入babel-ast
let deps = [];
//处理import esm转cjs
const ast = parse(source, { sourceType: "module" });
traverse.default(ast, {
ImportDeclaration({ node }) {
deps.push(node.source.value);
}
});
const { code } = transformFromAst(ast, null, {
presets: ["env"]
});
return { file, code, deps };
}
//3.读取依赖文件 循环处理
function main(path) {
//入口文件
const mainAsset = getFileInfo(path);
//依赖处理
let assets = new Set([mainAsset]);
for (const asset of assets) {
asset.deps.forEach((rpath) => {
const asset = getFileInfo(rpath);
assets.add(asset);
});
}
return Array.from(queue);
}
//4.输出code
function build() {
//打包的入口文件
const include = "./main.js";
const data = main(include);
//打包结果模板
const templet = `(function (modules,include) { function require(id) { const fn = modules[id];
const module = { exports:{} }; fn(require, module, module.exports); return
module.exports; } require(include); })({ <% data.forEach(info => { %> "<%=
info.file %>": function (require, module, exports) { <%- info.code %> }, <% })
%> },"<%= include%>");`;
const code = ejs.render(templet, { data, include });
fs.writeFileSync("./dist/bundle.js", code);
}
build();