- webpack打包原理分析和实现(一)
- webpack打包原理分析和实现(二)
- webpack打包原理分析和实现(三)
上一篇,通过@babel/parser将index中的es6代码解析成ast(抽象语法树),接下来,我们可以根据Body里面的分析结果,遍历出所有的引入模块,但是比较麻烦,这里推荐babel的一个模块@babel/traverse,帮我们处理。
分析单个模块依赖
npm i @babel/traverse --save
为了获得模块(文件)的依赖,通过ast可以看到依赖的路径存放在Node下面的resource的value里,我们需要提取ast中type为ImportDeclaration的Node,traverse中提供提取它的同名函数,回调参数为node的对象,我们把依赖的模块路径同意存放在dependencies 里,key为入口文件路径,值为项目里的全路径
代码语言:javascript复制moduleAnalyser(entryFile) {
//! 分析入口模块的内容
const content = fs.readFileSync(entryFile, 'utf-8')
console.log(content)
//!分析出哪些是依赖?以及依赖的路径
const ast = parser.parse(content, {
sourceType: 'module'
})
const dependencies = {}
traverse(ast, {
//提取哪个字段就用哪个函数
ImportDeclaration({node}) {
console.log(node.source.value)
//路径拼接
const newPathName = "./" path.join(path.dirname(entryFile), node.source.value)
dependencies[node.source.value] = newPathName
console.log(dependencies)
}
})
//console.log(ast.program.body)
}
打印结果为
代码语言:javascript复制./expo.js
./srcexpo.js
{ './expo.js': './src\expo.js' }
目前为止,通过moduleAnalyser这个方法,拿到了依赖的项目路径,存在dependencies对象中,供后续使用。
接下来,把代码处理成浏览器可运行的代码,需要借助@babel/core,和babel/preset-env,把ast语法树转换成合适的代码
代码语言:javascript复制npm i @babel/core @babel/preset-env --save
webpack中添加导入和代码
代码语言:javascript复制const babel = require('@babel/core')
const {code} = babel.transformFromAst(ast, null, {
presets: ['@babel/preset-env']
})
code为处理后的代码
导出所有分析出的信息
代码语言:javascript复制return {
entryFile,
dependencies,//如果没有值,说明没有依赖
code
}
moduleAnalyser 完整代码:
代码语言:javascript复制 moduleAnalyser(entryFile) {
//! 分析入口模块的内容
const content = fs.readFileSync(entryFile, 'utf-8')
console.log(content)
//!分析出哪些是依赖?以及依赖的路径
const ast = parser.parse(content, {
sourceType: 'module'
})
const dependencies = {}
traverse(ast, {
//提取哪个字段就用哪个函数
ImportDeclaration({node}) {
console.log(node.source.value)
// path.dirname(entryFile)
// console.log(path.dirname(entryFile))
//路径拼接
const newPathName = "./" path.join(path.dirname(entryFile), node.source.value)
console.log(newPathName)
dependencies[node.source.value] = newPathName
console.log(dependencies)
}
})
console.log(ast.program.body)
//! 处理内容,转换ast
const {code} = babel.transformFromAst(ast, null, {
presets: ['@babel/preset-env']
})
console.log('------------------------' code)
return {
entryFile,
dependencies,//如果没有值,说明没有依赖
code
}
}
分析所有模块依赖
- 根据webpack入口配置的options,获取入口模块,加入modules
- 遍历modules,判断是否有依赖,如果有,就拿到依赖的路径,通过moduleAnalyser,分析出依赖模块,加入到modules
- 分析最开始得到main.js,打包出的代码结构其实是一个对象,因此将modules转成对象结构
run() {//入口函数
const entryModule= this.moduleAnalyser(this.entry)
console.log(entryModule)
//!处理其他模块,做一个信息汇总
this.modules.push(entryModule);
for (let i = 0; i < this.modules.length; i ) {
const item = this.modules[i]
const {dependencies} = item
if (dependencies) {
for (let j in dependencies) {
this.modules.push(this.moduleAnalyser(dependencies[j]))//分析每个子模块的依赖
}
}
}
console.log(this.modules)
//! 数组处理成对象
const obj = {}
this.modules.forEach((item) => {
obj[item.entryFile] = {
dependencies: item.dependencies,
code: item.code
}
})
console.log(obj)//已完成分析入口依赖
// this.file(obj)
}
到这里,我们已经将依赖的各个模块转成了浏览器需要的信息,但是还是对象,需要进一步输出为代码文件,将在下一篇实现