学习笔记 part2-2

简单的 webpack 源码解析

  1. 初始化

    webpack-cli 解析配置文件和命令行参数,生成一份配置信息(options),经由lib/webpack.js接收options并实例化一个compiler控制整个构建流程,随后通过WebpackOptionsApply初始化一些内部插件如调用node进行读写的插件等

  2. compile

    经由compile进入编译流程。整个构建过程中webpack提供了tapable这个自带的基于事件流的任务处理库,在Compiler上挂载各个生命周期的事件钩子,以便在处理到某个阶段时触发回调函数。Compilation 是由 compiler 创建的单次构建过程的实例对象,Compiler 是控制从输入命令到完成输出的这整个生命周期,Compilation是把所有处理成 modules 的过程,Compiler周期内会反复触发 Compilation 实例.

    run(callback) {
        // 调用 run 方法后进入编译,并挂上回调函数
        this.compile(onCompiled);
        // ...
    }
    
    compile(callback) {
        //初始化compilation
        const compilation = this.newCompilation(params);
        // ...
    }
    
  3. make

    Compiler 在 make hook 被触发时,开始进入编译构建。以 entry 为入口,生成一个module对象,然后通过ast工具生成语法树对象,通过分析节点,递归生成module,并形成依赖关系。

    compiler.plugin("make", (compilation, callback) => {
        // 调用 compilation.addEntry 进入
        compilation.addEntry(this.context, dep, this.name, callback)
    })
    
    moduleFactory.create({},(err, module) => {
        //处理源码
        this.buildModule()
        //处理module建的依赖关系
        this.processModuleDependencies()
    })
    
  4. buildModule

    buildModule 是 make过程的核心,此过程主要完成3个任务:

    1. 通过runLoaders匹配loader规则和处理方法
    
    runLoaders({
        resource: this.resource,
        loaders: this.loaders,
        context: loaderContext,
        readResource: fs.readFile.bind(fs)
    }
     
    
    1. 通过ast工具,把源码解析成AST树
    
    // 根据js代码获取ast语法树对象
    ast = acorn.parse(code, parserOptions);
    
    
    1. 分析语法树节点递归生成新module,并产出一个树结构的module
    
    // 根据ast加载模块的依赖
    this.prewalkStatements(ast.body);
    this.walkStatements(ast.body);
    
    
  5. seal & createChunkAssets

    build完成, 通过调用 Compilation.seal 方法,开始组装编译后的内容。在这个阶段,开始将modules组成chunk,并执行一些挂载在此阶段钩子上的插件,比如tree-shaking等优化代码大小的插件。封装完成chunk后调用Compilation.createChunkAssets,将源码和模板代码生成待打包的最终代码内容

    
    createModuleAssets(){
        for (let i = 0; i < this.modules.length; i++) {
            const module = this.modules[i];
            if (module.buildInfo.assets) {
                for (const assetName of Object.keys(module.buildInfo.assets)) {
                    const fileName = this.getPath(assetName);
                    this.assets[fileName] = module.buildInfo.assets[assetName];
                    this.hooks.moduleAsset.call(module, fileName);
                }
            }
        }
    }
    
    
  6. emitAssets

    Compilation.emitAssets 方法触发 Compiler 的 emit hook。通过自带注册的文件读写插件,最终将之前生成的内容作为文件输出到配置信息中的目录,自此完成整个构建的流程。

    
    // 获取资源输出的路径
    outputPath = compilation.getPath(this.outputPath);
    // 递归创建输出目录并输出资源
    this.outputFileSystem.mkdirp(outputPath, emitFiles);
    
    
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容