仅用了81行代码,实现一个简易打包器
前言
最近打算跳槽到大厂,webpack打包流程必须了解,于是尝试一下手写一个打包器
准备工作
1. 3个js文件
index.js -> 依赖 subtraction.js => 依赖 sum.js
2. 5个npm依赖包
代码
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