美文网首页
frontendmasters webpack-plugins

frontendmasters webpack-plugins

作者: 云峰yf | 来源:发表于2018-11-12 10:45 被阅读0次

    Tapable Plugin System

    • webpack 是由插件组成的
    • Tapable 是 webpack 的基石,编写和注册插件都离不开它,之前是靠 compiler 实例
    • 继承了 Tapable 实例的类被称为 Tapable 实例
    • 在类里有若干静态钩子,改善了之前的开发体验(把方法挂载到原型上),因此,所有不同的事件都是 webpack 生命周期的不同部分。
    • .tap 就像 .plugin 的等价物,通过访问 compiler.hooks.compilation 来做一些事情

    Compiler & Compilation

    • 有七个最重要的 Tapable 实例
    • 第一个是 compiler,中央调度级别的,控制 webpack 的启动、构建完成、发射资产等,要访问其他实例必须通过它。
      • 如果使用 node api,会得到 compiler.run 实例
    • 第二个是 Compilation,最复杂的部分。是 webpack 构建依赖图的起点。
    • 这是作用域提升的地方,也是我们摇树和所有启发式的地方。

    Resolver & Module Factories

    • 第三个是 resolver,你给它一个部分路径,它会确保它存在,然后给你完整的绝对路径。
      • Resolver 实际上是你可以在 webpack 之外使用的东西。
    • 第四个是 Module Factories,他们所做的只是创造实例。
      • normal 模块工厂和 context 模块工厂,它们之间的区别在于支持动态 import 语句中的表达式
      • 它将从文件中提取源代码。将它存储在内存中的这个模块对象中,

    Parser & Templates

    • 第五个是 Parser,将一串源代码转换为我们称之为AST或抽象语法树的代码。
      • https://astexplorer.net/ 在线预览效果
      • Webpack 默认使用 Acorn 作为解析器获得 token
      • 解析器从模块工厂获取这个模块对象,将其转换为 AST,然后开始遍历图。
    • 第六个是 Templates,做数据绑定。
      • chunk、module、dep 都有模板,会调用一个名为 render 的函数。
      • 最终得到一些 iife 函数

    Compiler Walkthrough

    • 我们将配置传递给 webpack,它读取 entry 属性。
    • 我们不知道该条目是否存在,所以我们必须通过正常的模块工厂,该工厂调用解析器返回完整的路径信息,以及其他一些上下文和有用的数据,并将其传递回正常的模块工厂。
    • 然后工厂创建了这个对象,收集源信息,现在我们有了模块的源代码。
    • 接着解析器将代码解析为 AST。它遍历图形查找依赖语句,找到它时,它会附加到模块。
    • 这是一个广度优先的搜索图遍历。重复这个过程,直到没有更多的依赖关系来解决。
    • 最后进入渲染部分,依赖模板和依赖工厂把能执行在浏览器的代码生成。
    • 可以把它分成三个主要阶段,或者像三个步骤。一:构建图。二:优化图,三,渲染它,我们只使用模板,所以它是数据绑定。

    Plugin System Code Walkthrough

    • tappable 实例会先调用 compiler.run,然后应用配置
    • 里面有一个巨大的 switch 语句,用于创建不同的代码
    • 接着在 Complier.hooks.entryoption.call 触发入口选项钩子,为依赖设置模板
    • 最后得到一个模块,但钩子里可以插入不同的逻辑,得到不同的模块
    • AST 的每个部分都会触发一个事件
    • 实际上就是添加依赖项实例并将它们绑定在一起
    • 创建一个解析器插件、创建一个依赖项工厂,就可以做任何事情了。每个依赖实例都有一个模板
    • 修改 AST 很慢,因此我们选择做的是使用模板进行字符串转换。

    Creating a Webpack Plugin

    • 插件只是一个实例,或者它是一个具有 apply 方法的类。
    • complier.hooks + 事件 + 触发方式写回调
    • stats 是一个类,它有 Webpack compilation 实例。它告诉我们开始时间,整个包的哈希等有关构建的所有内容。
    class MyFirstWebpackPlugin {
        apply(compiler) {
            compiler.hooks.done.tapAsync("MyFirstWebpackPlugin", (stats, cb) => {
                const assetNames = [];
                for (let assetName in stats.compilation.assets) {
                    assetNames.push(assetName);
                }
                console.log(assetNames.join("\n"));
                cb();
            });
            compiler.hooks.compilation.tap("MyFirstWebpackPlugin", (compilation, params) => {
                new MyFirstWebpackCompilationPlugin().apply(compilation);
            });
        }
    }
    class MyFirstWebpackCompilationPlugin {
        apply(compilation) {
            compilation.hooks.seal.tap("MyFirstWebpackPlugin", () => {
                debugger;
            });
        }   
    }
    module.exports = MyFirstWebpackPlugin; 
    

    Plugin Instance Hooks

    • 如何插入不是 compilation 的东西呢?想插入不同的实例,仍然需要通过 compilation。
    • render 之前先是 seal 阶段
    • 在 NormalModuleFactory.beforeResolve 挂钩子改变引用的模块
      • 比如 ContextReplacementPlugin,将 moment 从部分路径中解析
      • 还有 NormalModuleReplacementPlugin

    Isolating Plugins

    • webpack 不调用文件系统,而是调用 MemoryFile 系统:memory-fs
    • 如此抽象,就可以将源码存进 redis 或者 mongo 了
    • 对于 resolver.resolve 的例外,不会做任何解析器调用。
      • 比如可以使用 get 虚拟文件系统并编写一个解析器,用来完全替换 webpack 的解析器
    • 一个插件可以应用另一个插件,从而隔离每个插件的功能集

    Creating a Custom Loader

    • 添加一个名为 resolveLoader 的属性
    • 应用于解析模块的任意自定义行为,可以为你的加载器执行相同的操作。
    • 有同步、异步,补丁 loader
    • 如果你想在加载器之间共享公共 AST,那么传递一个抽象语法树作为第四个参数可以加快构建时间。

    Configuring Babel for Webpack

    • 使用 babel 会破坏 webpack 所有对 ES 模块的优化,所以用 babel 请设置 preset 的 module 为 false

    Webpack Dev Kit & Wrap Up

    留下了一个示例项目:Webpack Developer Kit

    相关文章

      网友评论

          本文标题:frontendmasters webpack-plugins

          本文链接:https://www.haomeiwen.com/subject/obuqfqtx.html