// 获取主入口文件
const fs = require('fs')
// 引入生成ast 关键模块
const parser = require('@babel/parser')
const path = require('path')
// 引入遍历ast 得到的import路径 将其放入deps中(将用到的依赖收集起来)
const traverse = require('@babel/traverse').default
// ES6的AST转化成ES5
const babel = require('@babel/core')
// 分析模块的方法
const getModuleInfo = (file)=>{
const body = fs.readFileSync(file,'utf-8')
//分析模块 生成AST
const ast = parser.parse(body, {
sourceType: 'module' // 这个类型表示我们要解析ES模块
})
// 收集依赖
const deps = {}
traverse(ast,{
ImportDeclaration({node}){
const dirname = path.dirname(file)
const abspath = './' + path.join(dirname,node.source.value)
deps[node.source.value] = abspath
}
})
// 将ES6的AST转化成ES5
const { code } = babel.transformFromAst(ast, null, {
presets: ['@babel/preset-env']
})
// 将获取到的file deps(依赖) ES5 导出
const moduleInfo = {file,deps,code}
return moduleInfo
}
// 递归获取依赖方法
const parseModules = (file) => {
const entry = getModuleInfo(file)
const temp = [entry]
// 将文件路径为key {code, deps}为值存入对象
const depsGraph = {}
for( let i = 0; i<temp.length; i++) {
const deps = temp[i].deps
if(deps) {
for(const key in deps) {
if (deps.hasOwnProperty(key)) {
temp.push(getModuleInfo(deps[key]))
}
}
}
}
// 将文件路径为key {code, deps}为值存入对象
temp.forEach(item => {
depsGraph[item.file] = {
deps: item.deps,
code: item.code
}
})
return depsGraph
}
// 整合完整的字符串代码
const bundle = (file) =>{
const depsGraph = JSON.stringify(parseModules(file))
return `(function (graph) {
function require(file) {
function absRequire(relPath) {
return require(graph[file].deps[relPath])
}
var exports = {};
(function (require,exports,code) {
eval(code)
})(absRequire,exports,graph[file].code)
return exports
}
require('${file}')
})(${depsGraph})`
}
const content = bundle('./src/index.js')
fs.mkdirSync('./dist');
fs.writeFileSync('./dist/bundle.js',content)