注册

仅用了81行代码,实现一个简易打包器

前言

最近打算跳槽到大厂,webpack打包流程必须了解,于是尝试一下手写一个打包器

准备工作

1. 3个js文件

index.js -> 依赖 subtraction.js => 依赖 sum.js

ccf675a5371d4e7e8bcc490f67ccb50b~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

2. 5个npm依赖包

82b1a2282b5f4db296e175bd1533ac0a~tplv-k3u1fbpfcp-zoom-in-crop-mark:1304:0:0:0.awebp?

代码

const path = require("path")
const parser = require("@babel/parser")
const traverse = require("@babel/traverse").default
const fs = require("fs")
const { transformFromAst } = require("babel-core")
const config = {
   entry: "./src/index.js",
   output: {
       path: "./src/",
       filename: "build.js",
  },
}
const { output } = config
let id = 0
const createAsset = (entryFile) => {
   // 读取文件
   const source = fs.readFileSync(entryFile, "utf-8")
   // 代码转为ast,为了转换成ES5
   const ast = parser.parse(source, {
       sourceType: "module",
  })
   const dependents = {}
   // 借用traverse提取文件import的依赖
   traverse(ast, {
       ImportDeclaration({ node }) {
           dependents[node.source.value] = node.source.value
      },
  })
   // es6语法转es5
   const { code } = transformFromAst(ast, null, {
       presets: ["env"],
  })
   return {
       entryFile,
       dependents,
       code,
       id: id++,
       mapping: {},
  }
}
const createGraph = (rootPath) => {
   // 从根路径出发,获取所有与根路径相关依赖存放到modules中
   const mainAsset = createAsset(rootPath)
   const modules = [mainAsset]
   const dirname = path.dirname(rootPath)
   for (let asset of modules) {
       const { dependents } = asset
       for (let dep in dependents) {
           const childPath = path.join(dirname, dependents[dep])
           const childAsset = createAsset(childPath)
           asset.mapping[dependents[dep]] = childAsset.id
           modules.push(childAsset)
      }
  }
   return modules
}
// 转换一下数据结构
const createModules = (graph) => {
   const obj = {}
   graph.forEach((item) => {
       obj[item.id] = [item.code, item.mapping]
  })
   return obj
}
// 生成文件
const writeFiles = (modules) => {
   // 编译模板,modules是不固定的,其他都一样
   const bundle = `
   ;(function (modules) {
       const require = (id) => {
           const [code, mapping] = modules[id]
           const exports = {}
           ;(function (_require, exports, code, mapping) {
               const require = (path) => {
                   return _require(mapping[path])
               }
               eval(code)
           })(require, exports, code, mapping)
           return exports
       }
       require(0)
   })(${JSON.stringify(modules)})
   `
   // 生成文件
   const filePath = path.join(output.path, output.filename)
   fs.writeFileSync(filePath, bundle, "utf-8")
}
const graph = createGraph(config.entry)
const modules = createModules(graph)
writeFiles(modules)


作者:SYX
来源:juejin.cn/post/7091225169120722952

0 个评论

要回复文章请先登录注册