手写webpack核心(js打包)

134 阅读1分钟

手写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();