frontendmasters webpack-plugins

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,158评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,600评论 1 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,785评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,655评论 0 220
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,075评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,002评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,146评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,918评论 0 211
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,671评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,838评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,318评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,636评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,343评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,187评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,982评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,126评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,934评论 2 279

推荐阅读更多精彩内容