0%

Ivy-Angular下一代渲染引擎

The-Ivy-rendering-engine-in-Angular-cover-image

截止到2018年11月30号,根据is-angular-ivy-ready显示,Angular Ivy 已经完成了93.46%,基本上接近完工。但是国内对 Ivy 介绍却很少,这次把今年4月ng-conf2018中关于 Angular Ivy 的PPT翻译一下,希望让更多人了解到和 Angular Ivy 有关的一些信息。

点击可以查看PPT

2018-11-30_18-49-49

正如 Brad 先前提到的,Angular 的价值观以我们的用户,开发者和社区为中心。 Ivy 的目标是为 Angular 的价值观服务。

  • Ivy 专注于用户,通过让浏览器下载更少的资源,使应用程序启动更快,来提高用户体验。
  • 它通过简化 API 和构建系统来帮助开发人员。
  • 最后,它通过使编译管道更友好来帮助社区,从而为第三方贡献提供了可能性。

这些目标要求我们对编写代码的方式有不同的看法,并且我们希望与你分享这将为你的应用程序带来的结果和好处。

2018-11-30_21-53-47

但首先,不要害怕! 我们在这里所做的工作是100%向后兼容的,因此你不必对你的应用程序进行任何更改。 你的升级体验将与你对 Angular 团队的期望一样顺畅。 升级版本后,你将获得新的好处,并且你的应用程序仍然能很好的工作。 升级到 Ivy 意味着你的应用程序将继续工作而不会进行任何更改。 将有新的 API让你可以利用 Ivy 的一些更高级的功能。

2018-11-30_21-58-22

现在,当我说Ivy向后兼容时,我真的想要强调它的重要性。 在谷歌,我们现在有超过600个应用程序,它们都是构建在新的Angular之上。 我们还有一个版本政策,这意味着我们不允许在旧版本的Angular上保留现有的应用程序。 因为我们每天都在将Angular同步到Google,所以所有应用程序都需要每次同步之后继续工作。 我们几乎不可能做出一个破坏性的改变。 因此,当你获得代码时,你可以确信它已被现实世界的应用程序充分验证过。

2018-11-30_22-03-27

Ivy 有很多东西,但 Ivy 背后的一个重要思想就是我们所谓的 “locality”。简而言之,这意味着当编译器翻译模板时,只允许使用对它来说 “local” 的信息。local 意味着只有与组件描述直接关联的信息。这与当前 Angular 渲染管道的全局优化方法形成对比。那么让我们来谈谈 locality 给 Angular 带来的一些好处:

  • Locality 允许第三方库将预编译模板发送到 NPM。这很重要,因为对于使用这些库的应用程序来说,它将极大地简化和加速编译。
  • 有了 locality ,AoT / JIT的区别变得很小,几乎消失了。允许一个人自由地混合使用两者,例如在测试和开发中。对于生产,我们仍然只推荐 AoT。
  • Locality 不再需要Metadata.json文件。这极大地简化了第三方库的发布和开发以及与现有工具链的互用性。
  • Locality 大大修剪了编译图。这允许简化构建工具并更快地重建大型项目。
  • 而我个人的最爱:Locality 支持元编程。今天,无法在运行时创建组件,Ivy 将成为可能。一个元编程的例子是高阶组件。 (不仅仅是为了让HOC成为可能而倡导HOC。)

Locality 只是我们对 Ivy 坚持的一个原则。还有其他原则,但我们没有时间在这里讨论它们。

2018-11-30_22-42-58

“today”是指2018年4月18日。

你可以看到Ivy开始于runtime,与模板编译器的工作重叠。一旦完成这些,beta版将开始进行Google的内部验证流程。此验证过程包括确保Ivy不会对使用Angular的600多个内部应用程序进行重大更改。这确保了在Ivy发布之前将完全向后兼容。

下面是 Ivy 核心开发者 Kara Erickson 的PPT介绍

2018-11-30_22-45-56

Ivy 那么改变了什么?除了 Locality 之外,主要的变化是新系统的设计考虑了 tree-shaking。换句话说,渲染器代码的重写方式使得你未使用的任何 Angular 代码都可以简单地在构建步骤中被 tree-shaking 掉。这真的令人兴奋,因为这意味着你将留下一个更小的bundle。

我们正在进行的更改都在幕后 - 所以作为 Angular 开发人员 - 你实际上不必更改你正在编写的代码。但我会花一些时间来解释这个新设计是如何工作的,因为它实际上非常酷,我真的希望你理解为什么你会看到,使用 Ivy 后比用现在版本的 Angular 会得到更好的结果。

让我们先谈谈 tree-shaking。

如果你还没有听说过 tree-shaking,那么它本质上是一个构建优化步骤,可确保未使用的代码不会最终出现在你发送到浏览器的最终包中。通常,未使用的代码来自第三方库。

2018-11-30_23-15-58

2018-11-30_23-16-24

举一个简单的例子,如果你在第三方库中使用someFn,但是在这里没有使用过unusedFn,一个 tree-shaking 工具可以确保unusedFn不会在你最终的 bundle 中。

有一些工具可以做到这一点,比如:

  • rollup,它使用 live code inclusion 来确保未使用的代码不会添加到你的 bundle 中
  • Uglify,它分析已经打包的代码并尝试从中删除没有的代码

无论你选择哪种工具,它们的功效取决于你编写代码的方式。 我会告诉你我的意思。

2018-11-30_23-23-06

例如,假设你有一个从第三方导入的someFn,它在你的main函数中使用。

tree-shaking 通常使用引用的静态分析来确定要在 bundle 中保留哪些代码。

因为someFnmain函数中被引用,所以它将保留在 bundle 中。 UnusedFn不是,所以它不会在最终的 bundle 中。

2018-11-30_23-23-24

但是我们换一个场景,如果只有条件检查通过,你才能使用unusedFn

当你运行代码时,条件将最终为false,因此你仍然不需要unusedFn。 它会从 bundle 中删除吗?

答案是否定的,因为在main中引用了unUsedFn。 请记住,tree-shaking 通常使用引用的静态分析。 它将尝试在不实际运行程序的情况下找出所需内容,并且存在限制。 通常,它必须假设最坏的情况以确保生成的程序是正确的,因此在这种情况下,它不确定该值在运行时将是什么,所以将保留unusedFn

因此,当我们编写框架代码时,我们必须考虑避免这种情况。

2018-11-30_23-32-42

Ok,有了上面的铺垫,让我们回到渲染管道以及它是如何被重构的。 首先,快速概述当前渲染器的工作原理。

目前,你编写的模板 HTML 通过 Angular 编译器运行,并生成代表模板结构的高度优化的JS 代码。 在运行时,此数据结构将传递给 Angular 解释器,Angular 解释器使用数据来确定如何创建DOM。

2018-11-30_23-36-22

在实践中,它看起来像这样。 假设你有一个hello world模板,它只是一个带有classdiv

2018-11-30_23-37-51

当前,编译器可能生成类似这样的东西,一些defs代表模板的结构。 例如,viewDef 包含divelementDefhello worldtextDef

2018-11-30_23-40-50

然后在运行时将此定义传递给 Angular 解释器,Angular 使用该def来确定要运行哪些操作以正确生成DOM。

这非常有效。 唯一的问题是每个Angular模板都经过相同的代码路径,因此解释器不会提前知道它将看到哪种模板。 因此,它需要检查是否需要为其提供的模板执行每个操作。

正如我们之前所述,因为静态分析的工作方式,这些条件检查在运行时的值是什么并不重要,这里引用的所有函数都将保留在最终的 bundle 中,即使在代码路径中是没用过。

2018-11-30_23-45-42

当我们设计 Ivy 时,我们考虑到了这个问题。 当我们不能提前知道你的模板长什么样子时,我们如何确保未运行的代码不包含在 bundle 中?

这里有一个聪明的解决方案。 不生成模板数据并将其传递给解释器,然后解释运行哪些操作。

2018-11-30_23-50-14

我们直接生成一组模板指令。 这些指令将完成自己正确创建DOM的工作。 因此,我们不再需要一个解释器来检查是否需要每个操作,并且引用未使用的函数。

2018-11-30_23-52-49

对于和之前相同的模板,我们可能会生成这样的东西。 有三个指令:

  • elementStart - 它将在DOM中创建元素
  • text - 将在DOM中创建文本节点
  • elementEnd - 基本上会执行一些内部处理

2018-11-30_23-55-08

所以现在如果你看一下Angular代码,我们不需要进行任何条件检查。 我们只有原子函数来转换DOM,并根据你编写的模板生成。

2018-11-30_23-56-23

因此,如果你没有使用某些Angular功能,例如containerlistenerpipe……他们的指令就不会从你编写的模板中生成。 因为它们尚未生成,所以不会有引用,并且可以通过 tree-shaking 安全地删除它们。

2018-11-30_23-58-19

我们已经将这个策略用于我们可以想到的每个功能。因此,如果你不使用queries或结构指令或生命周期钩子,那么可以通过 tree-shaking 工具删除该代码。

2018-12-01_00-00-48

这真的很酷,因为这意味着你只需要关注实际使用的 Angular 特性,同时你的 bundle 大小可以显着缩小。 这反过来可以提高你的应用程序的启动性能,我知道很多人都在关注。

2018-12-01_00-04-05

生成指令的另一个好处是 Ivy 生成的代码更容易阅读和理解。 为什么这很重要?

2018-12-01_00-05-02

如果你能够理解并完成框架对代码执行的操作,则可以更轻松地调试 Angular 应用程序。

在2018 ng-conf 上 Angular团队给出了一个 ivy 的 todo 应用的 demo :ivy-todo-list,这个应用的 bundle 大小是12.2kb,这个 todo app 的 demo 就在github angular 的仓库中,地址:https://github.com/angular/angular/tree/master/packages/core/test/bundling/todo;

这个todo 在本地跑起来需要安装 Bazel , 然后通过 bazel 去运行这个app。

2018-12-01_00-13-14

你喜欢这些演示吗? 所以非常神奇的东西正在为 Ivy 而来。 我对 Ivy 的承诺感到非常兴奋,这是我们最重要的事情。

在我们将这个演示文稿包起来之前,我想解决一下我们与 Brad 一起做的旧赌注。 早在2016年5月,是两年前 Brad 向你们所有人做出了这个承诺。

2018-12-01_00-15-12

有些人可能还记得这张幻灯片。 是的,如果我们得到10Kb以下的Angular Hello World,Brad就会答应一块蛋糕。 布拉德没有说明它是 minified 还是压缩后的数字,但可以肯定地说我们击败了两者。

2018-12-01_00-17-43

这个 Todo 应用压缩后12.2 Kb。

2018-12-01_00-19-13

在当前的Angular中,压缩的Hello World大约为36 Kb,而Kara已经发现我们的hello world 最小化后 7.3kb,压缩后 2.7kb。 所以 Ivy 成功地击败了10KB的门槛。 我们不仅仅是刚刚跨过这个门槛,而是大幅度地超过这个门槛。

欢迎关注我的其它发布渠道