创建依赖关系
本节全部代码
js
// webpack\cheny-pack\lib\Complier.js
let path = require('path')
let fs = require('fs')
class Complier {
constructor(config) {
// 将配置文件挂载到实例上,所有实例都能拿到了
// webpack.config.js
this.config = config
// 1. 保存入口文件的路径
this.entryId; // './src/index.js'
// 2. 需要保存所有模块的依赖
// 解析文件的依赖,变成webpack打包传递的参数,key value的形式
// key 是路径名,value就是模块代码
this.modules = {}
this.entry = config.entry // 入口路径
this.root = process.cwd() // 工作路径 运行 npx cheny-pack 时候的路径
}
run() {
// 执行,并且创建模块的依赖关系
// 从入口开始执行
this.buildModule(path.resolve(this.root, this.entry), true) // true 表示解析的是主模块
// 发射一个文件 打包后的文件
this.emitFile()
}
// 创建模块的依赖关系
buildModule(modulePath, isEntry) {
// 模块的key是相对路径 value是模块中的代码,不过需要做一些替换
// require都变成了webpack_require等
let source = this.getSource(modulePath) // 模块内容
// 模块id是一个相对路径 总路径 减去 rootPath
// 总路径modulePath F:\code\note_code\webpack\webpack-dev-3\src\index.js
// 工作路径this.root F:\code\note_code\webpack\webpack-dev-3
let moduleName = './' + path.relative(this.root, modulePath) // ./src/index.js 模块id
if (isEntry) { // 如果是主入口的话,记录一下主入口的id
this.entryId = moduleName // 保存入口的名字
}
// path.dirname(moduleName)获取父路径 ./src/index.js -> ./src
// 解析模块代码,替换相应的内容
let { sourceCode, dependencies } = this.parse(source, path.dirname(moduleName))
// 把相对路径和模块中的内容对应起来
this.modules[moduleName] = sourceCode
}
// 解析文件
// 需要把source源码进行改造 返回一个依赖列表
// 因为每一个模块里面还可能会引另外的模块,所以需要一个依赖列表
parse(source, parentPath) { // AST 解析语法树
console.log(source, parentPath);
return {}
}
// 发射文件
emitFile() { }
// 获取模块代码
getSource(modulePath) {
return fs.readFileSync(modulePath, 'utf8')
}
}
module.exports = Complier
总结
这一节开始构建模块,主要做了几件事
读取模块代码
js// 1. 配置文件中,拿到主入口的路径 this.buildModule(path.resolve(this.root, this.entry), true) // true 表示解析的是主模块 // 2. 从主入口开始解析,fs.readFileSync 读取源代码 getSource(modulePath) { return fs.readFileSync(modulePath, 'utf8') } // 3. 读取 let source = this.getSource(modulePath) // 模块内容
获取模块的id
js// 1. 工作路径 工作路径 运行 npx cheny-pack 时候的路径 this.root = process.cwd() // 2. 模块id是一个相对路径 通过总路径 减去 工作路径来获取 // 总路径modulePath F:\code\note_code\webpack\webpack-dev-3\src\index.js // 工作路径this.root F:\code\note_code\webpack\webpack-dev-3 // path.relative(this.root, modulePath) 计算出的结果为 src\index.js,所以再拼接一个 ./ let moduleName = './' + path.relative(this.root, modulePath) // ./src/index.js 模块id
保存主入口的id
jsif (isEntry) { // 如果是主入口的话,记录一下主入口的id this.entryId = moduleName // 保存入口的名字 }
搭架子,分析接下来需要做的事
js// path.dirname(moduleName)获取父路径 ./src/index.js -> ./src // 解析模块代码,替换相应的内容 let { sourceCode, dependencies } = this.parse(source, path.dirname(moduleName)) // 把相对路径和模块中的内容对应起来 this.modules[moduleName] = sourceCode // 解析文件 // 需要把source源码进行改造 返回一个依赖列表 // 因为每一个模块里面还可能会引另外的模块,所以需要一个依赖列表 parse(source, parentPath) { // AST 解析语法树 console.log(source, parentPath); return {} }
因为原本webpack打包是自己封装的一个require方法,我们只需要往里塞内容即可。
我们写的require全部需要替换成
__webpack_require__
,并且路径全部变为了./src
开头的,所以需要使用path.dirname(moduleName)获取父路径 ./src/index.js -> ./src
,接下来的事就是开始解析源码了解析源码需要用到AST语法树,下一节学习
参考
https://www.bilibili.com/video/BV1a4411e7Bz?p=35&spm_id_from=pageDriver