User:星耀晨曦/存档/发展MediaWiki平台:为什么我们要用HTML5解析器取代Tidy(Wikimedia Blog)

三年前,维基媒体基金会的Parsing团队决定用基于HTML5的工具取代Tidy(这是一种修复HTML错误的工具)。在这篇博客文章中,我们将探讨如何花费时间去完成替换,这也揭示了对维基媒体的维基的某些技术基础设施进行更改有多复杂。

Castle Cary catch points - 02

三年前,Parsing团队决定用基于HTML5的工具取代Tidy(修复HTML错误的工具)。如果给定一个HTML5库,替换Tidy非常简单。但我们花费了三年时间才终于完成了转换。在这篇博客文章中,我们将探讨如何花费时间去完成替换,这也揭示了对维基媒体的维基的某些技术基础设施进行更改有多复杂。

此替换是Parsing团队、Platform团队、社区联络团队与维基媒体基金会的其他个人(来自产品方面)和各个维基上的志愿者编辑社群之间的合作。所有参与者让我们达到这里程碑发挥了重要的作用。在这篇文章中,作者使用“我们”作为叙述方便来指代上面的一些人群。

第一:背景

编辑

什么是Tidy?

编辑

Tidy是一个修复HTML标记的库。它是在20世纪90年代开发的,那时HTML 4是最新标准而且当时不同的浏览器处理错误的HTML的行为也不同。

当编者在模板和页面本身上使用HTML时,写下错误的HTML是很常见的。(比如常见的未闭合错误,结束标签不是</small>)。在某些情况下,MediaWiki本身会引入HTML错误。为了解决这个问题,Tidy在2004年左右被引入MediaWiki,以确保MediaWiki的渲染输出是格式良好的HTML,并确保它在不同的浏览器中呈现相同的效果。

Tidy让MediaWiki内核的wikitext解析器不在担心生成错误的HTML,从而可以专注于性能,这在在MediaWiki的早期开发中发挥了非常重要的作用。它还使我们不必编写和维护自定义解决方案,这一点非常重要,因为大多数MediaWiki的开发都依赖于志愿者。

为什么我们要替换掉它?

编辑

今天的技术领域与MediaWiki早期的2004年截然不同。首先,HTML5是当今的标准,并且明确指定了HTML5的解析算法,这实现了跨浏览器和其他库的兼容实现。该算法还明确指出了如何修复损坏的标记。

HTML4 Tidy已经多年不再维护。它基于HTML4,因此它偏离了最新的HTML5标准。此外,它还会造成与修复HTML错误无关的更改。例如,它在删除空元素的时候在HTML标签之间添加空格,这有时会改变渲染效果

虽然现在Tidy有了tidy-html5使其与HTML5兼容,但此版本继续执行与修复HTML错误无关的其他修正。鉴于此,我们认为:

  • 我们希望控制此工具的维护,以便我们选择何时以及如何升级它。这很重要,因为我们希望控制对wikitext行为的更改并为此更改做好准备。
  • 在MediaWiki对可视化编辑的支持中,当编辑的HTML转换回wikitext时,必须避免对wikitext进行虚假的更改。为了支持这一点,Parsoid(一种替代wikitext解析器将成为未来几年默认的解析器)使用标准的HTML5解析库,并依赖于能够精确地跟踪和映射生成的HTML以输入wiki文本。Tidy-html5,对HTML进行了额外的更改,这让情况变得更复杂,而且不适合Parsoid的HTML5库。
  • 随着MediaWiki本身的发展,我们希望使用基于DOM的策略来解析wikitext(我们目前基于字符串解析)。但Tidy目前没有为我们提供DOM。
  • 最后,我们希望保留能够在不影响正确性和功能的情况下将一个HTML5库替换为另一个HTML5库的灵活性。不符合预期的HTML更改限制住我们,导致我们不能简单的替换库(就如当前项目那样)。

因此,虽然Tidy这些年来一直很好地为我们服务,但现在是时候升级到与MediaWiki的技术发展路径更加兼容的不同解决方案了。

我们用什么来取代Tidy?

编辑

经过一系列的实验,我们最终决定用RemexHtml取代Tidy,RemexHtml是HTML5树构建算法的PHP实现。这是由维基媒体基金会的Parsing团队和Platform团队开发并维护的。RemexHtml利用Parsoid使用的一个domino node.js库和早期开发的Html5Depurate中原始的Tidy替换解决方案。

自从2004年开始在维基媒体wiki上启用Tidy以来,所有这些wiki上的wiki标记都巧妙地依赖于一些Tidy功能。为了简化Tidy的过渡,MediaWiki在RemexHtml之上实现了一些Tidy兼容性代码。例如,虽然RemexHtml不会删除空元素,但MediaWiki会使用CSS类标记它们,因此wiki可以选择隐藏它们以模仿Tidy的剥离行为。

是什么让这次替换变得困难起来?

编辑

有很多问题使得这个项目变得相当困难:

  1. 我们需要确定一个合适的HTML5库来取代Tidy。
  2. 我们必须构建测试基础设施,以准确评估此更改将如何影响维基媒体wiki上的页面呈现。
  3. 然后我们必须解决我们在测试过程中发现的任何变化所造成的影响。

确定合适的替代库

编辑

首先,PHP中没有合适的HTML5树构建算法实现。唯一的候选人是html5-php,但它没有实现H5规范的一些关键部分。因此,我们最初把精力集中在维基媒体集群的wiki上,而不是作为MediaWiki的一个库。到2015年底,我们有了Html5Depurate,它是一个基于Java HTML5库validator.nu之上的包装库。对于那些对细节感兴趣的人,T89331记录了这个讨论。

在2016-2017时间框架内,Parsing团队的两个独立但有些重叠的工作合并到RemexHtml中,这就是HTML5解析算法的PHP实现。我们采用RemexHtml作为Tidy替代解决方案,因为它具有良好的性能和更广泛的适用性(可以不仅在维基媒体里使用)。

测试基础设施以判断对页面呈现的影响

编辑

由于wiki已经开始依赖Tidy,如果我们用HTML5工具取代Tidy,我们预计某些页面上的渲染效果会以某种方式发生变化。为了评估这种影响,我们建立了一个大规模的视觉差异化基础设施,其中包含两个MediaWiki实例(在云服务中运行):一个使用Tidy,另一个使用Tidy的代替品。这些实例运行了一个包含来自40个wiki的6万多个页面的多维基。在第三台服务器上,我们从这两个虚拟机中获取页面,使用PhantomJS对这些页面进行快照,并使用UprightDiff识别渲染中的差异,并将差异转化为可量化的数字分数

截至2016年5月底,经过几轮修复和测试后,我们发现了多种类型的渲染差异,而93%的页面在我们的测试子集中未受影响,7%的页面影响超出了我们的预期。因此,我们很清楚,在我们实际进行切换之前必须修复维基页面。所以,这现在突出了上面的第三个问题:我们如何才能实现这一目标?

我们为编者/维基提供了哪些工具和支持?

编辑

我们有三个问题需要解决:

  1. 确定需要修复的页面
  2. 需要在这些页面中修复什么
  3. 如何验证修复的结果

在实践中,我们的工作没有遵循这种理想的顺序,但是,我们最终为编辑提供了两个工具,即ParserMigrationLinter,它们解决了这些问题。

ParserMigration

编辑

为了让编者了解任何特定页面将如何受到更改的影响,2016年7月左右我们开发了ParserMigration扩展,它允许编者在预览页面的时候并排显示Tidy和Tidy的替代品(最初是Html5Depurate,现在是RemexHtml)的渲染效果。这使他们可以编辑页面并通过显示更新预览来验证编辑是否消除了所有的渲染差异。

Linter

编辑

Parsoid能够分析HTML并识别有问题的渲染输出,然后将其映射回生成它的wiki文本。基于此,GSoC学生在2014年制作了一个linting工具原型,2016年10月,我们决定将这个原型开发成Tidy替换项目的生产就绪的解决方案。到2016年底和2017年初,我们开发了Linter扩展为MediaWiki提供了一个Hook,从Parsoid接收linter信息,并通过wiki的Special:LintErrors页面向wiki上的编者提示哪些页面的哪段wikitext有问题。

我们分析了早期的视觉差异测试结果,并在Parsoid中添加了linter分类,以区别可能导致渲染差异的wikitext模式。我们在2017年7月开始使用三种linter分类,并最终在2018年1月之前根据其他测试和早期部署的反馈提供了9个高优先级的linter分类。

社群参与和分阶段的部署

编辑

在开发工具的同时,从2016年底到2017年中期,我们制定了一项计划,让编者在各个wiki来修复页面和模板,为Tidy替换做好准备。我们准备了一个FAQ,开始编写Linter帮助页面,编写了部署计划和时间表,完善并部署了RemexHtml、Linter和ParserMigration,起草了关于即将发生的变更的公告,并于2017年7月6日将其发送到几个邮件列表中科技新闻。我们给wiki提供了为期一年的窗口,以便开始对wiki进行修复,为替换Tidy做好准备。

我们计划根据Linter确定的潜在渲染问题的状态分阶段替换不同wiki上的Tidy。我们继续在他们的客栈、MediaWiki和Phabricator上与wiki合作。英语维基百科的测试帮助我们找到了一个我们忽略的渲染变化

我们将意大利语和德语维基百科作为两个大型wiki并经过他们的同意,于2017年12月5日进行切换渲染器。这个早期部署给了我们非常好的反馈——无论是积极的还是消极的。德语维基百科的部署完美无瑕,意大利语维基百科的部署暴露了一些问题,让我们新添了额外的Linter分类,以标记需要修复的页面。2018年1月部署到俄语维基百科的问题迫使我们改变围绕空白的wikitext语法来重现Tidy行为

编者和志愿者为他们开发了帮助页面和其他工具来帮助修复页面。从2018年4月开始,对于英语维基百科来说,我们帮助了个别维基项目,我们联系了包含大量高优先级别错误的wiki,帮助他们与志愿者联系,并提供有关如何提前解决错误的信息。我们中的一个人甚至在10个维基(主要是小维基)上修复了100个模板。

一直以来,我们继续收集相关wiki在修复页面方面取得进展的每周统计数据,并且还对wiki的内容进行每周视觉差异测试,以收集关于如何减少渲染在页面上的变化的定量数据。我们继续在wikitech-ambassadors邮件列表和技术新闻进行不定期更新,以便让所有人了解进展情况。

总的来说

编辑

这种持续的社群参与、沟通、测试、监控和分阶段部署工作对于让我们完成为期一年的维基切换部署窗口至关重要,同时尽可能减少对读者的干扰。同样重要的是,通过各个维基的积极合作,这项工作让基金会对我们平台的关键部分进行了重要的升级。

接下来是什么? 这启用了什么?

编辑

由于TemplateStyles的首选实现依赖于RemexHtml,因此这解锁了部署条件对已经切换到RemexHtml的编者来说是最直接的好处。MediaWiki中的一些错误修复已经从RemexHtml里真正的HTML5解析中受益,我们希望编者在使用他们自己编写的wikitext出现渲染问题时会发现正确的HTML5语法。展望未来,有两个平行的发展受益于RemexHtml:平衡模板,对于读者和编者来说它可以使输出更加可预测和更快;以及计划把Parsoid从Node.js迁移到PHP。最终,当我们开始考虑如何发展wikitext以获得更好的工具、性能、推理能力和更少的错误时,基于DOM的解决方案将非常重要。

但所有这一切都在未来。目前,我们很高兴能够成功实现这一里程碑!

作者

编辑