Web Component 實踐 - EE NEXT SDK

引言

本文檔主要描述 EE NEXT SDK 團隊使用 Web Component 開發前端組件的技術決策,並穿插一些 Web Component 技術標準如 CustomElement、Shadow DOM 的優缺點介紹和踩坑經驗。

EE NEXT SDK 是什麼?

EE NEXT SDK 是字節跳動 - 效率工程 - 中臺前端團隊開發的一款功能性前端業務組件合集,它能夠將效率工程中臺團隊的 AI 搜索、員工信息查詢、AI 信息增強等能力以前端組件形式對外輸出。

EE NEXT SDK 包含諸如搜索、員工卡片以及知識卡片等多個具有配套後端服務的前端業務組件,只提供 CDN 接入方式,因此業務線在使用 SDK 時通常會以如下形式接入。

<!document>
<head>
    <script async src="https://{{cdn-host}}/{{cdn-path}}/user-card-v1.0.0.js"></script>
</head>

EE NEXT SDK 在 Web Component 上的實踐

Web Component 簡要介紹

Web Component 是 W3C 支持的前端組件開發規範,包含 CustomElement、Shadow DOM、Slot 以及 HTML Template 等標準 API 和特性。

Web Component 能讓前端開發人員實現跨技術棧和跨瀏覽器使用的前端組件,目前市面上佔有率較高的瀏覽器均支持這一特性。

爲什麼在 EE NEXT SDK 中使用 Web Component

Web Component 的跨端和跨技術棧特性,以及天然的樣式隔離,能夠解決長久以來中臺前端組件存在的通病:

技術背景

NEXT SDK 團隊需要開發一款新的員工卡片前端組件,用於展示公司 / 組織內的人員信息如姓名、郵箱和工作城市等。

技術挑戰

開發新員工卡片需要應對的幾個問題:

跨技術棧和跨端使用

員工卡片會被多個商業化應用如飛書招聘、飛書 OKR 等集成,不同業務線可能使用 React15、React16 甚至 Vue.js 作爲技術棧。

爲了能夠適應不同業務環境的技術棧,甚至於瀏覽器端、WebView 等環境也需要適配,新員工卡片的技術體系需要具備高兼容性。

組件編譯體積要儘可能小

作爲一款第三方 SDK,NEXT SDK 裏的每一款組件都是一個單獨的 JavaScript 文件,因此對組件文件大小提出了較高的要求,應儘量避免體積過大帶來加載時間長的問題。

樣式保護

如果無法做到組件自身的樣式保護,勢必會被不同業務環境的樣式所影響,導致反覆出現組件展示錯誤,造成不必要的返工。

易用性

新員工卡片技術體系需要實現組件化,以降低用戶的使用成本,組件的聲明、實例化、卸載以及副作用的管理都不是也不應該是業務線 RD 所關心的。

不侵入業務開發環境

不需要業務線 RD 修改自身項目構建流程,完全解耦

傳統 React 組件開發方式能否滿足新員工卡片的技術場景?

Web Component 能夠解決什麼問題

  1. 兼容性高。作爲瀏覽器原生支持的技術標準,使用 Web Component 開發的前端組件天然能夠無視技術棧和瀏覽器等差異,在大多數環境下均能正常使用。

  2. 體積小。Web Component 不需要像 React.js 、Vue.js 和 jQuery 等引入大體積 Runtime 文件,所有組件的聲明、實例化和銷燬均由瀏覽器負責,能夠使得最終編譯體積足夠小。

  3. 樣式隔離。Web Component 體系下的 Shadow DOM 能爲組件元素提供天然的樣式保護,Shadow DOM 下的子元素不會被外部樣式選中,也不會受到外部 JavaScript 影響,最大程度降低了出現樣式問題的概率。

  4. 使用簡單。使用 Web Component 開發的組件可如普通 HTMLElement 元素一樣使用,無需特殊處理,使用起來與日常操作 DOM API 較爲接近。

  5. 穩健性高。尤其是在微前端架構下具有明顯的優勢,不會因爲子應用頻繁切換、元素重建和銷燬造成 Web Component 組件出現副作用卸載不及時或組件無法重新掛載問題。

最終決策

Web Component 是什麼

Web Component 開發離不開 CustomElement 和 Shadow DOM 兩大主力,下面將對這兩個概念進行簡單介紹。

快速上手

以下內容將用 CodeSandbox 演示 Web Component 組件簡單開發流程,流程包括 CustomElement 和 Shadow DOM 使用,主要開發內容爲:

創建 CustomElement

核心步驟

使用 Shadow DOM 用於保護樣式

核心步驟

  1. 在 custom-button 下掛載一個 Shadow Root

  2. 在 Shadow Root 內添加一個樣式表,使其能夠影響 Shadow DOM 內元素,同時不影響外部

https://codepen.io/weidongxin/pen/MWmNgOb

最終頁面結構

CustomElement

CustomElement 能夠讓開發者快速地創建可複用的 Web 前端組件,並能夠如操作普通 HTMLElement 元素一樣,新增、修改和銷燬組件。

優勢

不足

class CustomButton extends HTMLElement { xxx };
// 定義 custom-button 元素
window.customElements.define('custom-button', CustomButtom);
const customButton = document.body.querySelector('custom-button');

// 傳遞引用類型 props
customButton.message = { name: 'xxx' };
customButton.setParams({ age: 23 })
// Home.tsx
// 以下示例無法在 custom-button 上註冊一個類型爲 popout 的 CustomEvent
const Home: FC = (props) ={
    const onPopout = () ={};
    return <custom-button onPopout={onPopout}></custom-button>
};

// 需進行如下改造
const Home: FC = (props) ={
    const onPopout = () ={};
    const ref = useRef<HTMLElement | null>(null);

    useEffect(() ={
        if (!ref.current);
        ref.current.addEventListener('popout', onPopout);
        return () ={
            ref.current.removeEventListener('popout', onPopout);
        };
    }[ref]);

    return <custom-button ref></custom-button>
};

Shadow DOM

Shadow DOM 可以將一個 “隱藏” 的、獨立的 DOM 元素附着至其他元素下,ShadowDOM 內部的樣式、行爲都不會影響至外部。同樣地,外部的樣式、行爲對 ShadowDOM 內部的影響 “有限”。

優點

作用

Shadow DOM 天生的樣式隔離能力,使得它較爲適合用於充當第三方前端組件的保護傘,尤其適合 EE Next SDK 的應用場景。

使用 Shadow DOM 時的常見誤區和解決方案

1. Shadow DOM 並非完全樣式隔絕

儘管 Shadow DOM 能夠阻止外部樣式表選中其中的子元素,但不能避免 CSS 屬性繼承,如圖所示:

示例

優化方法

https://codepen.io/weidongxin/pen/NWgpJPJ

2. Light DOM 、Shadow DOM 和 Slot

Light DOM 概念介紹

Light DOM 這一術語通常出現於存在 Shadow DOM 的場景中,主要指代 Shadow DOM 宿主元素下的所有子孫節點,用於同 Shadow DOM 作區分。

Slot

類似於 Vue.js 中的插槽概念,能夠將 Shadow DOM 宿主元素下的子孫節點(即 Light DOM)引用至 Shadow DOM 內,將被引用的 DOM 元素 “復刻” 一份並渲染。

Light DOM 和 Shadow DOM 不能同時被渲染
問題表現

若宿主元素下同時存在 Light DOM 和 Shadow DOM,通常情況下會觀察到在頁面上沒有正確渲染出 Light DOM 。

https://codepen.io/weidongxin/pen/ExvyzVd

問題原因

Shadow DOM 與 Light DOM 不能共存,若兩者同時存在則通常情況下 Light DOM 不會被渲染。

解決辦法

3. Shadow DOM 並非 CustomElement 專屬

儘管 Shadow DOM 是屬於 Web Component 標準中的一部分,但它並未被限制只能在 CustomElement 下使用,即便是普通 HTMLElement 也能夠使用這一技術來實現樣式保護。

4. Shadow DOM 並不會造成莫名其妙的樣式問題

Shadow DOM 只是一個具有樣式隔絕功能的外衣,大多數情況下都不會造成宿主元素、 Shadow DOM 以及被引用的 Light DOM 的樣式錯誤。一旦出現了明顯的樣式問題,需要以常規 CSS 樣式處理的思路解決問題。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/F5P0hySgkjQ2LEowwQfSsw