步骤
- 读取入口文件 entry
- 拿到文件依赖, @babel/parser
- 遍历出所有的引入模块 @babel/traverse
- 转化为浏览器可以识别的代码 @babel/core @babel/preset-env
- 分析依赖
- 生成代码
- 写入输出文件目录
myWebpack.js
const fs = require('fs')
const parse = require('@babel/parser')
const { transformFromAst } = require('babel-core')
module.exports = class Webpack{
constructor(options){
this.entry = options.entry
this.output = options.output
}
run(){
// 递归找到moduleArr
const info = this.build(this.entry)
const moduleArr = []
moduleArr.push(info)
for(var i=0;i<moduleArr.length;i++){
const item = moduleArr[i]
const {dependencies} = item
if(dependencies){
for(const key in dependencies){
moduleArr.push(this.build(dependencies[key]))
}
}
}
// 转成对象
const obj = {}
moduleArr.forEach(module=>{
obj[module.entry] = {
code:module.code,
dependencies: module.dependencies
}
})
this.emitFile(obj)
}
// 读取文件 拿到依赖
build(entry){
const entry = fs.readFileSync(entry, 'uft-8')
// 转成ast数
const ast = parser.parse(entry,{
sourceType: 'module'
})
const dependencies = {}
// 依赖
tranverse(ast, {
importDeclaration({node}){
const dirname = path.dirname(entry)
const newPath = './' + path.join(dirname,node.source.value).replace(/\///g,'/' )
dependencies[node.source.value] = newPath
}
})
// 转化为浏览器可执行的代码
const {code} = transformFromAst(ast, null, {
preset:['@babel/preset-env']
})
return {
code,
dependencies,
entry
}
}
emitFile(obj){
// eval code
// 转成字符串
const objStr = JSON.stringify(obj)
const boundle = `
(function(modules){
var exports = {}
funciton localRequire(relativePath){
return require(modules[moduleId].dependencies[relativePath])
}
(function(require, exports, code){
eval(code)
})(localRequire, exports, modules[moduleId].code)
require('${this.entry}')
})(${objStr})
`
fs.writeFileSync(filename, boundle)
}
}