Web Component 实践 - EE NEXT SDK

583次阅读  |  发布于3年以前

引言

本文档主要描述 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 样式处理的思路解决问题。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8