Skip to content

创建依赖关系

本节全部代码

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

总结

这一节开始构建模块,主要做了几件事

  1. 读取模块代码

    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) // 模块内容
  2. 获取模块的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
  3. 保存主入口的id

    js
    if (isEntry) { // 如果是主入口的话,记录一下主入口的id
        this.entryId = moduleName // 保存入口的名字
    }
  4. 搭架子,分析接下来需要做的事

    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方法,我们只需要往里塞内容即可。

    image-20220203151614711

    我们写的require全部需要替换成__webpack_require__,并且路径全部变为了./src开头的,所以需要使用path.dirname(moduleName)获取父路径 ./src/index.js -> ./src,接下来的事就是开始解析源码了

  5. 解析源码需要用到AST语法树,下一节学习

参考

https://www.bilibili.com/video/BV1a4411e7Bz?p=35&spm_id_from=pageDriver