webpack是一个打包模块化JavaScript的工具,在webpack里一切文件皆模块,通过Loader转换文件,通过Plugin注入钩子,最后输出由多个模块组合成的文件。webpack专注于构建模块化项目。
# 简单版打包模型步骤
我们先从简单的入手看,当 webpack 的配置只有一个出口时,不考虑分包的情况,其实我们只得到了一个bundle.js的文件,这个文件里包含了我们所有用到的js模块,可以直接被加载执行。那么,我可以分析一下它的打包思路,大概有以下4步:
- 利用
babel完成代码转换及解析,并生成单个文件的依赖模块Map - 从入口开始递归分析,并生成整个项目的依赖图谱
- 将各个引用模块打包为一个立即执行函数
- 将最终的
bundle文件写入bundle.js中
# 单个文件的依赖模块Map
- 我们会可以使用这几个包:
@babel/parser:负责将代码解析为抽象语法树@babel/traverse:遍历抽象语法树的工具,我们可以在语法树中解析特定的节点,然后做一些操作,如ImportDeclaration获取通过import引入的模块,FunctionDeclaration获取函数@babel/core:代码转换,如ES6的代码转为ES5的模式
由这几个模块的作用,其实已经可以推断出应该怎样获取单个文件的依赖模块了,转为
Ast->遍历Ast->调用ImportDeclaration。代码如下
// exportDependencies.js
const fs = require('fs')
const path = require('path')
const parser = require('@babel/parser')
const traverse = require('@babel/traverse').default
const babel = require('@babel/core')
const exportDependencies = (filename)=>{
const content = fs.readFileSync(filename,'utf-8')
// 转为Ast
const ast = parser.parse(content, {
sourceType : 'module'//babel官方规定必须加这个参数,不然无法识别ES Module
})
const dependencies = {}
//遍历AST抽象语法树
traverse(ast, {
//调用ImportDeclaration获取通过import引入的模块
ImportDeclaration({node}){
const dirname = path.dirname(filename)
const newFile = './' + path.join(dirname, node.source.value)
//保存所依赖的模块
dependencies[node.source.value] = newFile
}
})
//通过@babel/core和@babel/preset-env进行代码的转换
const {code} = babel.transformFromAst(ast, null, {
presets: ["@babel/preset-env"]
})
return{
filename,//该文件名
dependencies,//该文件所依赖的模块集合(键值对存储)
code//转换后的代码
}
}
module.exports = exportDependencies
@前端进阶之旅: 代码已经复制到剪贴板
可以跑一个例
