跳至內容

Wikimedia Blog:发展MediaWiki平台:为什么我们要用HTML5解析器取代Tidy

維基百科,自由的百科全書

三年前,維基媒體基金會的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的解決方案將非常重要。

但所有這一切都在未來。目前,我們很高興能夠成功實現這一里程碑!

作者[編輯]