上一篇,通過@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爲入口文件路徑,值爲項目裏的全路徑
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)
}
打印結果爲
./expo.js
./src\expo.js
{ './expo.js': './src\\expo.js' }
目前爲止,通過moduleAnalyser這個方法,拿到了依賴的項目路徑,存在dependencies對象中,供後續使用。
接下來,把代碼處理成瀏覽器可運行的代碼,需要藉助@babel/core,和babel/preset-env,把ast語法樹轉換成合適的代碼
npm i @babel/core @babel/preset-env --save
webpack中添加導入和代碼
const babel = require('@babel/core')
const {code} = babel.transformFromAst(ast, null, {
presets: ['@babel/preset-env']
})
code爲處理後的代碼
導出所有分析出的信息
return {
entryFile,
dependencies,//如果沒有值,說明沒有依賴
code
}
moduleAnalyser 完整代碼:
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)
}
到這裏,我們已經將依賴的各個模塊轉成了瀏覽器需要的信息,但是還是對象,需要進一步輸出爲代碼文件,將在下一篇實現