Web Components實踐:如何搭建一個框架無關的AI組件庫

一、讓人又愛又恨的Web Components

Web Components是一種用於構建可重用的Web元素的技術。它允許開發者創建自定義的HTML元素,這些元素可以在不同的Web應用程序中重複使用,並且具有自己的樣式、行爲和功能。

Web Components並非一項新技術,而是一組持續演進的、由W3C標準化的組件化API。最早可以追溯到2011年左右,大約在2016年左右各個瀏覽器才實現了Custom Element V1版本。然而,在同一時期,諸如Vue和React等組件化框架已經開始主導前端開發生態。

儘管近幾年Web Components標準和技術都趨於成熟,但早期面臨的兼容性問題以及後來Vue和React等MVVM框架的崛起,導致Web Components領域一直處於低調狀態。接下來,我們將從Web Components的發展歷程、優勢以及開發中面臨的挑戰三個方面更深入地瞭解Web Components。

1、Web Components發展歷程

2011年:Google發佈了Chrome瀏覽器,並提出了“Shadow DOM”概念,這是Web Components的一個重要組成部分。
2013年:谷歌工程師Alex Komoroske在Google I/O大會上首次提出了Web Components的概念,並推動了相關標準的制定。
2014年:W3C發佈了Web Components的規範草案,其中包括四個主要技術:Custom Elements、Shadow DOM、HTML Templates和HTML Imports。
2015年:Web Components的規範逐漸得到瀏覽器廠商的支持,Chrome、Firefox、Safari等主流瀏覽器開始逐步實現相關功能。
2018年:Web Components逐漸成爲前端開發的主流技術之一,越來越多的開發者開始使用Web Components來構建可重用的組件。
至今:Web Components技術不斷髮展和完善,越來越多的框架和庫開始支持Web Components,使其在前端開發中發揮更大的作用。

2、Web Components有哪些優勢

封裝性:Web Components 具有良好的封裝性,可以將頁面中的功能和樣式封裝在一個自定義元素內部,避免全局作用域的污染,提高了代碼的可維護性和可重用性。
跨框架兼容:Web Components 是基於 Web 標準的技術,可以在任何支持 Custom Elements 和 Shadow DOM 的現代瀏覽器中使用,與各種前端框架和庫兼容性良好。
標準化:Web Components 的規範由 W3C 組織制定,具有較高的標準化程度,有利於統一前端開發的規範和實踐,提高了代碼的可維護性和可移植性。
性能優勢:通過使用 Shadow DOM 技術,Web Components 可以實現更好的性能優化,避免不必要的重繪和重排,提高頁面的渲染效率和用戶體驗。

目前,前端開發中有許多流行的框架可供選擇,如React、Vue、Angular、Solid、Svelte、Preact等。框架的選擇是一個複雜的決策過程。當框架版本升級時,項目可能需要面臨重構的問題。例如,從Vue2升級到Vue3可能需要付出較大的改造成本。如果不進行升級,就無法使用最新特性,甚至可能面臨框架舊版本不再維護的尷尬局面。在這種情況下,Web Components 的框架無關性可以在一定程度上改善這種局面。

就性能而言,以將 React 組件轉換爲 Web Components 爲例,可以優化執行過程,減少阻塞,提高頁面性能。在普通的 React 組件中,初次執行時需要一次性完成所有必須的節點邏輯,這些邏輯的執行會同步佔用在 JavaScript 的主線程上。當頁面變得足夠複雜時,一些非核心邏輯可能會阻塞後面核心邏輯的執行。而通過使用 Web Components 優化 React 組件,執行過程會變得更簡潔。例如,註冊一個複雜的邏輯組件時,在 React 執行時只需執行一個 createElement 語句,創建組件只需要 1-2 微秒即可完成。真正的邏輯不會立即執行,而是等到“核心任務”執行完畢後再執行,甚至可以在合適的時機再執行,從而降低 Diff 成本





 

3、使用Web Components開發的痛點

雖然Web Components具有許多令人喜歡的優點,但在實際開發中也存在一些棘手的問題。以下是幾個典型問題:

原生開發難題:Web Components是一項原生技術,因此在組件編寫過程中需要回歸到原生開發。事件處理、狀態管理等方面都需要自行處理。儘管大多數框架都提供了對Web Components的封裝方案,但使用這些方案又需要引入相應框架的運行時,這導致脫離了框架無關性這一最大優勢。
Form表單問題:在Shadow DOM中,包含<input>、<textarea>或<select>等標籤的value不會自動與表單關聯,因此在表單提交時無法獲取相應的value,需要手動處理,另外 ElementInternals提案 也在致力於解決這個問題。
樣式隔離問題:雖然樣式隔離有助於避免全局樣式污染的問題,但在某些場景下,如主題顏色等,仍需要將樣式同步到Web Components組件內部。目前可以通過CSS變量實現主題切換。此外,需要注意的是,slot插槽中的DOM元素樣式並未得到隔離。

針對這些問題,開發人員可能需要考慮採取一些額外的措施來解決挑戰,以確保Web Components在實際應用中能夠更加順暢地運行。

二、目前主流的Web Components組件方案

1、頭部案例

Twitter

Twitter 2016 年開始將自己的嵌入式推文從 iframe 切換成 ShadowDOM,減少了內存消耗、加快了渲染速度,並批量渲染的時候保持絲滑。Upcoming Change to Embedded Tweet Display on Web

Youtube

Youtube 作爲 google 系的產品,很早就在全站用上了 Web Components,並且開源了自己播放器組件 GitHub - GoogleWebComponents/google-youtube: YouTube video playback web component此外 google 開源的 Web Components 還是很多的,Google Web Components · GitHub ,包括地圖、drive、日曆等等。

Github

Github 對 Web Components 的使用很早,具體可以看: How we use Web Components at GitHub | The GitHub Blog,2017 年 Custom Elements v1 版本在 chrome 和 safari 上相繼實現之後,Github 開始大範圍使。要知道 Github 2018 年纔剛剛完全移除 jQuery:Removing jQuery from GitHub.com frontend | The GitHub Blog 這既得益於 Github 自身項目組件化的架構,也得益於 Web Components 本身與框架無關的特性非常識合作老項目升級。

Adobe Spectrum

Adobe Spectrum 是由 Adobe 創建的設計系統,該站點是一個基於 Web Components 的 UI 框架產品。

2、方案對比

目前主流的 Web Components 組件方案有三種:

方案一:

特點:以React和Vue爲代表,通過將React或Vue組件包裝爲Web Components組件的方式實現。
優點:利用了本身框架的特性如生命週期、狀態管理等,易於開發者使用。
缺點:需要引入本身框架的運行時,導致組件體積增加,同時喪失了框架無關性這一優勢。

方案二:

特點:以Stencil和LitElement爲代表,提供了專門的編譯器、工具鏈和語法糖來構建 Web Components。
優點:相比第一種方案,引入本身框架的運行時可能更小,減少了體積。
缺點:需要學習新的語法和工具,可能增加開發者的心智負擔。

方案三:

特點:以Svelte和Solid爲代表,直接將組件編譯成原生 Web Components

優點:放棄了虛擬DOM,利用編譯或轉譯能力直接生成操作DOM的更新函數,性能優秀,接近原生DOM。另外Vue3中的Vapor模式,正是借鑑了這種模式,目前正在試驗階段。

三、與SolidJS結合的“化學反應”

1、SolidJS有何不同

SolidJS 是一個快速、靈活、可擴展的 JavaScript 庫,用於構建用戶界面。與其他前端框架相比,SolidJS 有一些獨特的特點和優勢:

Reactivity System: SolidJS 使用基於數據變化的響應式系統,可以精確追蹤狀態的變化,並只更新發生變化的部分,從而提高性能。
Fine-grained Reactivity: SolidJS 提供了細粒度的響應式更新,可以在組件級別、元素級別甚至屬性級別進行更新,避免不必要的重新渲染。
No Virtual DOM: 與其他框架不同,SolidJS 不使用虛擬 DOM,而是直接編譯生成操作真實 DOM的函數,減少了 diff 算法的開銷,提高了性能。
Hooks-based API: SolidJS 使用類似 React Hooks 的 API,使得組件邏輯更易於複用和組合

2、可以解決哪些問題

直接在編譯階段生成原生Web Components,核心庫非常小巧,沒有額外的依賴,可以幫助減少項目的體積。
提供響應式狀態管理、事件管理、生命週期等,解決原生開發的痛點。
類React語法,上手容易,降低開發者心智負擔,轉換成Web Components十分流暢。

四、從0到1搭建 Aura Design Web Components組件庫

1、工程目錄設計

該項目採用了 Monorepo 設計,旨在統一管理各個子項目,避免開發階段頻繁發佈/安裝 npm 包來同步代碼。具體內容包括:

packages/eslint-config-aurai: 用於管理ESLint配置,集成了TypeScript和Prettier(用於JavaScript/TypeScript格式化)。
packages/stylelint-config-aurai: 用於管理StyleLint配置,集成了stylelint-order(用於樣式屬性排序)和Prettier(用於樣式格式化)。
packages/aura-design: 基於eslint-config-aurai和stylelint-config-aurai規範,使用Solid和Solid Element構建的Web Components元組件庫,包括按鈕、圖標、卡片、佈局等基礎組件。
packages/aura-design-pro: 與aura-design類似,但封裝了一些複雜組件,通常是依賴第三方庫的組件,例如支持Markdown渲染的富文本組件、視頻播放組件等。
apps/aura-design-docs: 基於Storybook的組件文檔庫,支持查看代碼、組件預覽,並可實時預覽修改組件屬性。
apps/react-starter、apps/vue-starter: 計劃用於驗證Web Components在React和Vue組件中的兼容性等問題。





 

2、部分細節展示

2.1、組件樣式編寫

Web Components組件中的樣式是內聯到每一個組件的Shadow DOM中,因此不能用常規的CSS Modules等方案。本項目中使用了大約4種不同的內聯樣式方案,以對應不同的應用場景:

原子化CSS方案:UnoCSS致力於將所有樣式屬性細分爲最小單元的CSS,以便實現最大程度的自由組合和複用。此外,UnoCSS還具有自動分析文件中使用的樣式的功能,只將實際使用的樣式打包,從而減小文件大小。





 

CSS inline模式:利用Vite的功能,將外部樣式作爲內聯模式引入,當需要自定義複雜樣式或語義化場景時,可能會使用此模式。
import styles from './Button.css?inline';
CSS Template:CSS模板字符串類似於CSS-in-JS方案,通常用於根據prop變量動態控制樣式。儘管這種方法會增加一定的運行時處理邏輯,但可以有效減少CSS重複和文件大小。
const styles = css`
  :host {
      display: inline-block;
  }
  .box {
      height: ${props.size + 2}px;
      line-height: ${props.size + 2}px;
      position: relative;
      overflow: hidden;
  }
  .nums-chip {
      transition: transform 1.5s;
      transform: translate(0, -50%);
      overflow: hidden;
  }
  .number {
      font-size: ${props.size}px;
      line-height: ${props.size + 2}px;
  }
`;
CSS Link:使用link標籤引入外部樣式表,當組件樣式比較多、體積較大時,如果直接內嵌到組件內部,當有N個組件時,體積就會增大N倍(暫不考慮瀏覽器內置優化邏輯),而使用link標籤減少體積同時也可以利用上瀏覽器緩存的特性。
...
return (
  <>
    <link href={`https://cdn.bootcdn.net/ajax/libs/highlight.js/11.8.0/styles/atom-one-${props.theme}.min.css`} rel="stylesheet"></link>
    <style>{styles}</style>
    <div innerHTML={md.render(props.text)}></div>
  </>
 );
...

2.2、Svg圖標集成

Icon組件引入和註冊

import {
 defineCustomElements,
 registerIcon,
 Icon,
} from '@aura-group/aura-design';
registerIcon('/iconfont.svg'); // 自定義svg圖標註冊,使用主項目根目錄的svg圖標文件,如果不註冊則使用默認圖標
defineCustomElements({ Icon }); // 註冊Web Components圖標組件

組件使用

<ar-icon name="download" size="20px" color="#4213de"></ar-icon>

2.3、組件打包

支持ES(按需加載)和UMD兩種範式,自動生成Typescript聲明文件:

package.json

{
 "name": "@aura-group/aura-design",
 "version": "0.3.9",
 "description": "",
 "main": "dist/aura-design.umd.js",
 "module": "dist/aura-design.es.js",
 "typings": "dist/types/components/index.d.ts",
 "files": [
 "dist"
  ],
 "type": "module",
...
}

Vite相關配置

...
build: {    
  lib: {
    entry: 'src/components/index.ts',
    name: 'aura-design',
    fileName: (format) => `aura-design.${format}.js`,
  },
},
...

3、基於Storybook的組件文檔

Storybook 是一個開源工具,用於開發和展示 React、Vue、Angular 等前端組件的交互式 UI 組件庫。通過 Storybook,開發人員可以在一個獨立的環境中編寫、展示和測試組件,而不必依賴於整個應用程序。這樣可以更快地開發和調試組件,同時也方便團隊成員之間的協作。

Storybook 提供了一個交互式的界面,開發人員可以在其中創建不同的“故事”(stories),每個故事對應一個組件的不同狀態或交互方式。通過 Storybook,開發人員可以輕鬆地查看和測試組件在不同狀態下的表現,從而更好地理解和調試組件的行爲。

Aura Design 組件庫文檔





 

4、未來規劃

目前,我們的組件庫中包含了16個基礎組件和一些與AI Chat相關的組件。在 A-M 網站中,95% 的組件都源自 Aura Design 組件庫。未來,除了繼續封裝一些基礎組件外,我們將優先開發常規組件庫中缺失的比如AI應用的相關組件。隨着組件庫的逐步豐富和條件的成熟,我們會考慮將其開源。如果您有任何相關組件的封裝需求或希望成爲項目的成員,請隨時與我聯繫。

參考文獻

ChatGPT
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章