自己写一个webpack
- 读取到配置入口
- 入口模块的路径
- 模块分析
- 模块的依赖(依赖的路径)
- 可以用递归的方式处理依赖模块
- 内容处理
- 依赖图谱对象(处理后的内容代码)
- webpackBootstrap函数
- 读取到配置出口
- 生成文件
- 文件存放的位置
- 文件的名称
webpaci.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "main.js",
},
mode: "development",
};
bundle.js (node bundle.js )
const webpack = require("./lib/webpack.js")
const options = require("./webpack.config.js")
new webpack(options).run()
webpack.js
const fs = require("fs")
const path = require("path")
const babelParser = require("@babel/parser")
const traverse = require("@babel/traverse").default
const { transformFromAst } = require("@babel/core");
module.exports = class webpack {
constructor(options) {
// console.log(options);
const { entry, output } = options
this.entry = entry
this.output = output
this.module = []
}
run() {
const info = this.parse(this.entry)
// console.log('🚀 ~ file: webpack.js ~ line 18 ~ webpack ~ run ~ info', info)
this.module.push(info)
for (let index = 0; index < this.module.length; index++) {
console.log('🚀 ~ file: webpack.js ~ line 22 ~ webpack ~ run ~ this.module', this.module)
const element = this.module[index];
const { yilai } = element
if (yilai) {
for (const key in yilai) {
// console.log('🚀 ~ file: webpack.js ~ line 26 ~ webpack ~ run ~ yilai', yilai)
if (Object.hasOwnProperty.call(yilai, key)) {
this.module.push(this.parse(yilai[key]))
// console.log(key, this.module);
}
}
}
}
// 数组转对象
const obj = {};
this.module.forEach(item => {
obj[item.entryFile] = {
yilai: item.yilai,
code: item.code
}
})
// console.log('🚀 ~ file: webpack.js ~ line 37 ~ webpack ~ run ~ obj', obj)
this.file(obj)
}
parse(entryFile) {
// console.log(entryFile);
const content = fs.readFileSync(entryFile, "utf-8")
// console.log(content);
const ast = babelParser.parse(content, { sourceType: "module"})
// console.log('🚀 ~ file: webpack.js ~ line 21 ~ webpack ~ parse ~ ast', ast)
// console.log(ast.program.body);
const yilai = {}
traverse(ast, {
ImportDeclaration({node}){
// console.log('🚀 ~ file:', node.source.value)
const pathName =
"./" + path.join(path.dirname(entryFile), node.source.value); // ./a.js ./b.js
yilai[node.source.value] = pathName
}
})
const { code } = transformFromAst(ast, null, {
presets: ["@babel/preset-env"],
});
// console.log('🚀 ~ file: webpack.js ~ line 39 ~ webpack ~ parse ~ code', code)
// console.log(yilai);
return {
entryFile,
yilai,
code
}
}
file(code) {
const filename = path.join(this.output.path, this.output.filename)
const newCode = JSON.stringify(code);
const bundle = `(function(graph){
function require(module){
function PathRequire(relativePath){
return require(graph[module].yilai[relativePath])
}
const exports = {};
(function(require,exports,code){
eval(code)
})(PathRequire,exports,graph[module].code)
return exports;
}
require('${this.entry}')
})(${newCode})`;
fs.writeFileSync(filename, bundle, 'utf-8')
console.log(filename);
}
}