我们计划更新 Discourse 中使用的 Ember 版本。
目前,我们使用的是 3.15,我们希望升级到 4.1。
我们的目标是在今年年底前完成这项工作。请注意,本主题是一个路线图,所有的计划和估算都是初步的。本主题不旨在就特定的升级或变更进行重大讨论。因此,让我们在这里保持对话的专注。关于这些更新将如何影响你的站点/插件/主题的问题属于离题内容。计划的变更 100% 仅涉及前端(Ember 应用)。
我们将非常谨慎地处理引入的变更。所有官方插件/主题都会得到更新**(包括 CDCK 为其客户进行的任何定制工作)**。我们还将发送 PR 来更新所有流行的非官方插件/主题。
如果你有一个为你站点构建的自定义插件/主题,也不用担心。我们会添加弃用警告,并及时发布必要的公告,以给你留出足够的时间来进行所需的变更。如果需要,我们也会尽力指导你完成这些变更。
让我们先从目标开始。我们显然希望达到可用的最高版本,但我们需要在现在和最终目的地之间设定中间目标。
我们计划进行增量更新。与其一次性进行到 4.1 的重大更新,我们将把这项工作分解为六个阶段。每个阶段专注于一次 Ember 更新。
| 阶段 | 规模 | 更新 |
|---|---|---|
| 1 | size-l | Ember 3.15 → Ember 3.16 |
| 2 | size-m | Ember 3.16 → Ember 3.25 |
| 3 | size-xl | Ember 3.25 → Ember 3.26 (第一部分 - 通用) Ember 3.25 → Ember 3.26 (第二部分 - 模板) Ember 3.25 → Ember 3.26 (第三部分 - jQuery) Ember 3.25 → Ember 3.26 (第四部分 - Octane 准备工作) Ember 3.25 → Ember 3.26 (第五部分 - Octane) |
| 4 | size-l | Ember 3.26 → Ember 3.27 (第一部分 - 通用) Ember 3.26 → Ember 3.27 (第二部分 - RenderTemplate) Ember 3.26 → Ember 3.27 (第三部分 - 遗留内置组件) |
| 5 | size-s | Ember 3.27 → Ember 3.28 |
| 6 | size-s | Ember 3.28 → Ember 4.1 |
选择这些特定版本完全基于它们引入的弃用项和工作量——以及隐含的风险。
因此,让我们进一步分解这些阶段以提供更清晰的说明。
每次更新的弃用项
阶段 1 (size-l)
Ember 3.15 → Ember 3.16
此更新仅引入一项弃用。
-
使用 ember-CLI 解析器而不是遗留全局解析器
- 截止:4.0.0 - size-lDiscourse 拥有自己的自定义 解析器,目前它扩展自
Ember.DefaultResolver。推荐的修复方法是放弃任何自定义解析器,并使用 Ember-CLI 的 解析器。说起来容易做起来难,因为我们有很多处理插件和主题的自定义逻辑。
一个可行的折衷方案是扩展 Ember-CLI 解析器,而不是扩展
Ember.DefaultResolver。
阶段 2 (size-m)
Ember 3.16 → Ember 3.25
此更新引入八项弃用。
-
使用 Ember getter 并显式检查 undefined
- 截止:4.0.0 - size-s这是一个简单的弃用。我们只需要从代码库中移除getWithDefault,我们使用它的地方只有几处。 -
String 原型扩展
- 截止:4.0.0 - size-m这也是一个简单、低风险的替换,但我们在很多地方使用了 Ember 扩展的 String 原型。快速检查后,我认为核心和插件/主题中大约有 < 100 处这样做的地方。一旦我们更新了这些,我们还应该通过类似以下方式防止 Ember 扩展该原型。EXTEND_PROTOTYPES: { String: false }在我们的 environment 文件中。
-
从 @ember/string 导入htmlSafe和isHTMLSafe
- 截止:4.0.0 - size-m此更新中与 #7 有大量重叠,应该直接且低风险。
阶段 3 (size-xl)
从 3.25 到 3.26 的升级相当复杂。这是我们进行大部分“追赶”的地方。总共有十六项弃用。我们将把这个更新分为五个部分——只有在处理完所有弃用项后,才进行版本提升。
Ember 3.25 → Ember 3.26 (第一部分 - 通用)
这部分处理九项相对容易处理的弃用。
-
路由和控制器中的转换方法
- 截止:5.0.0 - size-m此弃用项从
routes和controllers中移除了几个方法。它可能看起来是一个复杂的变更,但应该很直接。我们只需要在需要时将Router作为服务注入,并从那里调用它们即可。棘手的部分是我们在很多地方使用了这些方法,它们都需要更新。 -
浏览器支持策略
- 截止:4.0.0 - size-s~~这应该是一个相对简单的变更。Ember 从 4.0 开始将不再支持 IE11。这里的好消息是,我们很久以前就已经不再支持它了。我们需要做的唯一改变是停止在生产环境中为 IE11 进行转译。
discourse/app/assets/javascripts/discourse/config/targets.js at 1472e47aae5bfdfb6fd9abfe89beb186c751f514 · discourse/discourse · GitHub我做了一些基础测试,此变更将为我们节省约 60kb (gzip) 或生产 Ember-CLI 安装中主文件和 vendor 包的大约 ~6%。 -
{{hasBlock}} 和 {{hasBlockParams}}
- 截止:4.0.0 - size-s我们在几处使用了这些。这是一个简单、低风险的重命名。 -
{{with}}辅助函数
- 截止:4.0.0 - size-s我们很少使用这个,但它仍然需要修复。我们只需要替换它们并使用{{let}}或{{if}}/{{else}}的组合。
Ember 3.25 → Ember 3.26 (第二部分 - 模板)
这部分将主要关注涉及 .hbs 模板的弃用项。这里有三项我们需要关注的弃用项。
-
属性回退查找
- 截止:4.0.0 - size-l从 Ember 4.0 开始,这将不再有效。
Hello, {{name}}!如果我们在模板中有一个属性,我们必须使用前置的
this来查找它,如下所示Hello, {{this.name}}!我们必须对所有模板执行此操作。有一些方法可以减少这里的痛苦。我们可以尝试使用 ember-no-implicit-this-codemod,看看它能帮我们做到什么程度。
我倾向于将每次 PR 的变更限制在 1 个文件。这使得审查变得容易——如果出错,也易于回滚。
-
通过 {{attrs}} 访问命名参数
- 截止:4.0.0 size-xl{{attrs}}对象将在 Ember 4.0 中被移除。变更本身非常直接,Ember 的示例也非常不错。之前:
{{attrs.foo}} {{this.attrs.foo.bar}} {{deeply (nested attrs.foobar.baz)}}之后:
{{@foo}} {{@foo.bar}} {{deeply (nested @foobar.baz)}}我们必须对所有模板执行此操作。我们可以将此变更与将模板转换为尖括号语法结合起来。我非常喜欢尖括号,因为它们更接近标准的自定义 Web 组件语法。
可能加速我们在此方面进展的一件事是 ember-angle-brackets-codemod。我们将不得不对其进行实验,看看它能帮我们做到什么程度。它处理了弃用项,并为我们提供了漂亮的尖括号语法。
与此部分中的 #1 类似,我也倾向于每次 PR 修复和测试一个模板。
-
<LinkTo>位置参数
- 截止:4.0.0 - size-m这也是一个旨在减少混淆的弃用项。我们在几处使用了 link-to 的位置参数。我们可以像这样修复它们
之前:
{{link-to "About Us" "about"}} {{#link-to "about"}}About Us{{/link-to}} {{#link-to "post" @post}}Read {{@post.title}}...{{/link-to}}之后(使用尖括号):
<LinkTo @route="about">About Us</LinkTo> <LinkTo @route="about">About Us</LinkTo> <LinkTo @route="post" @model={{@post}}>Read {{@post.title}}...</LinkTo>
Ember 3.25 → Ember 3.26 (第三部分 - jQuery)
关于这一点,我没有太多可以说的,因为你们可能已经知道了。新的 Ember 应用不使用 jQuery,并且它将在 Ember 4.0 中被移除。
在这部分,我们将专注于一项弃用。
-
可选功能:jquery-integration
- 截止:4.0.0 - size-xl在过去几年里,我们在减少 jQuery 使用方面取得了巨大进展。仍然有一些地方我们需要它,特别是在编辑器中,以及作为我们使用的一些 vendor 库的依赖项。我不想在这里深入讨论此变更的细节。简而言之,我们应该远离使用 jQuery。
然而,我想强调的是,即使我们在 EVERYWHERE 都去掉了 jQuery,在我们准备好迎接 Ember 4.0 之前,我们仍应保持此选项设置为 true。我们需要一个计划来减轻对我们不控制的自定义主题/插件站点的过渡影响。换句话说,让我们完成工作,但忍受关于关闭该选项的弃用警告。
Ember 3.25 → Ember 3.26 (第四部分 - Octane 准备工作)
在这部分,我们应该专注于让我们的文件为 Octane 做好准备。我们将处理两项弃用。
-
可选功能:template-only-glimmer-components
- 截止:4.0.0 - size-m理论上这是一个简单的变更,但在我们可以切换该选项之前,我们需要做一些隐含的工作。
我们需要确保我们当前的仅模板组件与 glimmer 语义兼容。我做了一些测试,开启该选项后我们的测试失败了。以下是我们在核心中的一些仅模板组件的示例列表
- app/templates/components/activation-email-form.hbs - app/templates/components/cancel-link.hbs - app/templates/components/categories-with-featured-topics.hbs - app/templates/components/category-name-fields.hbs - app/templates/components/color-input.hbs - app/templates/components/custom-html-container.hbs - app/templates/components/emoji-group-buttons.hbs - app/templates/components/emoji-group-sections.hbs - app/templates/components/empty-state.hbs - app/templates/components/ip-lookup.hbs - app/templates/components/modal-footer-close.hbs - app/templates/components/popup-menu.hbs - app/templates/components/reviewable-created-by-name.hbs - app/templates/components/reviewable-created-by.hbs - app/templates/components/reviewable-field-editor.hbs - app/templates/components/reviewable-field-text.hbs - app/templates/components/reviewable-field-textarea.hbs - app/templates/components/reviewable-field.hbs - app/templates/components/reviewable-flagged-post.hbs - app/templates/components/reviewable-post-header.hbs - app/templates/components/reviewable-post.hbs - app/templates/components/reviewable-scores.hbs - app/templates/components/reviewable-tags.hbs - app/templates/components/reviewable-topic-link.hbs - app/templates/components/score-value.hbs - app/templates/components/selected-posts.hbs - app/templates/components/subcategories-with-featured-topics.hbs - app/templates/components/text-overflow.hbs - app/templates/components/user-fields/confirm.hbs - app/templates/components/user-fields/dropdown.hbs - app/templates/components/user-fields/multiselect.hbs - app/templates/components/user-fields/text.hbs - app/templates/components/user-profile-avatar.hbs - app/templates/components/user-summary-users-list.hbs我们还需要检查我们的 Admin/主题/插件模板,并确保在发布该选项之前一切正常。
凭直觉,我不确定我们的原始
.hbr模板将如何融入其中。然而,@david 一直在研究基于 glimmer 的主题列表。所以,也许我们可以完全摆脱原始模板。 -
隐式注入
- 截止:4.0.0 size-xl我们在各处都使用隐式注入。我们在初始化程序中像这样操作
discourse/app/assets/javascripts/discourse/app/pre-initializers/inject-discourse-objects.js at ac79c5efc61d259705eeb487ca21d0ec3c535807 · discourse/discourse · GitHubEmber 正在远离隐式注入。首选的前进路径是将尽可能多的对象转换为服务,并在需要时显式注入它们。当然,可能有一些地方服务并不理想。在这些情况下,我们可以在需要时直接查找这些对象,如下所示
getOwner(this).lookup('thing:main')我们还有另一个选项(取决于性能影响),即用我们自己的 Discourse 类包装 Ember 类。然后我们在整个应用中使用我们的类。就像我们对
GlimmerComponent Class所做的那样
https://github.com/discourse/discourse/blob/fa0c796baf9a7f64a3b27823b1aa4b370a74c3eb/app/assets/javascripts/discourse/app/components/glimmer.js。这将使此任务成为 size-l 甚至 size-m无论如何,此变更需要一些思考。
Ember 3.25 → Ember 3.26 (第五部分 - Octane)
这是 3.25 → Ember 3.26 升级的最后阶段。此时我们只剩下一项弃用,但它是一个大项。
-
Edition: Classic
- 截止:4.0.0 - size-xl在将我们的版本切换到 Octane 之前,我想花时间将我们的类转换为原生类,将我们的组件转换为 Glimmer 组件。这会带来一些痛苦,但这是值得的。ember-native-class-codemod 应该能减轻一些痛苦。我们将不得不看看它能帮我们做到什么程度。
有很多需要考虑的事项和工作流问题。我只想强调的是,它将遵循我为模板提到的相同流程——每次 PR 修复和测试一个组件。
阶段 4
Ember 3.26 → Ember 3.27 更新引入十二项弃用。我建议将它们分为三个部分。我们将在处理完所有弃用项后进行版本提升。
Ember 3.26 → Ember 3.27 (第一部分 - 通用)
-
弃用
Route#disconnectOutlet
- 截止:4.0.0 - size-s我们只在一处这样做。它是
build-category-route,修复它应该很直接。 -
在命名参数位置调用不带参数和括号的辅助函数
- 截止:4.0.0 - size-s我认为我们没有任何地方这样做,但到时候我会确认。本质上,调用辅助函数而不传递任何参数。
即使我们使用类似的东西,我们也只需要添加括号。所以,这个
<SomeComponent @arg={{someHelper}} />变成
<SomeComponent @arg={{(someHelper)}} />注意
someHelper周围的括号 -
运行循环和计算属性的点访问
- 截止:4.0.0 - size-m我们在
decorators插件中使用.来访问computed函数。它们看起来像这样,例如
discourse/app/assets/javascripts/discourse-common/addon/utils/decorators.js at b05fddaa7ce3968ffc70cd8d4bf290e15d06eb11 · discourse/discourse · GitHub我们这里和那里还有一些零散的一次性用法。据我所知,修复这些主要是关于修复我们导入它们的方式。
所以,
computed.filter应该像这样导入。import { filter } from '@ember/object/computed';我们外部 vendor
buffered-proxy插件的版本使用.来访问computed函数;我们需要提升它。我们在几处也使用
.来访问run函数。也就是说,同样的修复适用。我们需要更新我们导入它们的方式。我认为主题和插件特别可能有很多地方用run这样做 -
弃用 Ember 全局变量
- 截止:4.0.0 - (#size ?)Ember在 4.0 之后将不再在全局上下文中可用。在不深入查看的情况下,很难估计这里的工作量/影响。也就是说,我知道 @cvx 一直在做大量工作来消除这种模式。
Ember 3.26 → Ember 3.27 (第二部分 - renderTemplate)
这部分将仅专注于一项弃用。
-
弃用
Route#renderTemplate
- 截止:4.0.0 - size-l简而言之,我们不能在 Ember 4.0 中使用命名 outlet。所以,这将无效。
{{outlet "thing"}}仅在核心中,我们在近 30 处使用了
renderTemplate。升级本身似乎相当直接。我们可以使用{{#in-element}}和一个普通的空 HTML 元素作为我们过去在命名 outlet 中渲染的内容的占位符。
Ember 3.26 → Ember 3.27 (第三部分 - 遗留内置组件)
这部分将关注遗留内置组件,并将处理四项弃用。
我没有为这些添加规模,因为……这真的取决于。让我解释一下。
像 Checkbox、TextField、TextArea 和 LinkComponent 这样的遗留内置组件将在 Ember 4.0 中被移除。我们在很多地方使用了它们,我们也对它们使用了一些已弃用的模式。
Ember 提供了一条升级路径,允许我们继续使用它们,但我们必须以不同的方式导入它们。然而,它们将不会收到来自 Ember 的任何更新,并将保持冻结状态。我希望我们可以摆脱所有它们;然而,这可能有点复杂。此变更将在适当的时候需要更多讨论。
阶段 5
Ember 3.27 → Ember 3.28
这是一个 size-s,因为它只是一个版本提升。3.28 是 3.x 开发周期中的最后一个 LTS 版本。它在 3.27 之后没有引入任何新的弃用项,并且是一个适合我们暂停几周让事情稳定下来的好版本。
3.28 LTS 支持至 2022 年 8 月(包括错误修复和安全补丁)
此“休息”有几个好处。
- 它给我们更多时间查看是否会出现任何问题
- 当我们发布稳定版本时,它应该基于 3.28
- 它给我们时间发布任何关于我们需要自行维护的主题和插件的公告
- 它给我们时间确保 jQuery → 无 jQuery 的过渡尽可能平滑。
阶段 6
几周过后,我们终于可以提升我们的版本到 Ember 4
Ember 3.28 → Ember 4.1
我们现在可以关闭可选的 jQuery 集成,作为 3.x 周期的最后一项弃用。
此更新引入两项次要弃用。
-
弃用 Ember.assign
- 截止:5.0.0 - size-s我们在核心中未使用那个,但我们需要检查主题/插件。无论如何,这是一个简单的重命名。 -
AutoLocation 类
- 截止:5.0.0 - size-s理论上,我们只需要在我们的 Ember environment 文件中将
locationType: 'auto'更改为locationType: 'history',它就应该能正常工作。
工作流
正如我在开始时提到的,我们将非常谨慎地处理这些更新。我们将测试/修复/锁定所有官方插件/主题,并每次更新时,我们还将向流行的非官方插件/主题发送 PR。
这里的目标不是减慢开发速度或造成麻烦。因此,PR 应该是严格范围的,每次 PR 一个变更,没有太大的变更。
在理想的世界里,所有的变更都会在后台发生,而不打断其他人的工作。这就是为什么我们计划保持 PR 简短而甜蜜。此外,我们不太喜欢混合模式。因此,我们不想在逐文件的基础上陷入中间状态。一个组件要么是经典的,要么是 Glimmer,一个模板要么使用花括号,要么使用尖括号,没有中间状态。
我希望这份路线图清晰。正如我在开始时提到的,这只是一个一般的高级概述。如果有任何不清楚、不正确或让你感到不适的地方,请告诉我们。