Web Components真的能干掉React吗?一个后端老油条的前端探索

云端行者
2026-01-22 06:33
阅读 1397

凌晨两点,咖啡已经凉了第三杯,我盯着屏幕上那个被产品经理反复打回的支付组件发呆。这已经是本周第三次了——“能不能做成独立模块,让H5、小程序、甚至后台管理系统都能复用?” 我心里翻了个白眼:说得轻巧,我们主站是React,后台是Vue,移动端又是Taro,你让我怎么“一次开发,到处使用”?

我在这家金融科技公司干了三年多后端,日常和Kafka、Consul、Vault打交道,对安全性和系统稳定性有强迫症。但最近半年,因为团队在搞“全链路组件化”,我被迫开始啃前端。说真的,一开始看到Shadow DOM这种词,我以为是某个新出的加密算法。

从“被迫营业”到真香现场

事情的转折点发生在上个月。我们风控系统需要嵌入一个实时交易监控卡片,但前端资源紧张,后端又不能干等。技术总监丢给我一句话:“试试Web Components,原生支持,不用打包,安全可控。” 我当时内心OS:原生?那不就是90年代的HTML+JS吗?

结果一查资料,发现Web Components其实是一套现代浏览器原生支持的组件化标准,包含三个核心API:

  • Custom Elements:自定义标签
  • Shadow DOM:样式和DOM隔离
  • HTML Templates:声明式模板

最关键的是,它不依赖任何框架,天然支持跨框架复用。对于我们这种对第三方依赖极度敏感的金融系统来说,简直是救命稻草——少一个npm包,就少一个潜在的安全漏洞。

实战:把支付组件“原生化”

我拿手头最头疼的支付组件开刀。原来的React版本代码如下:

// React版(简化)
const PaymentWidget = ({ amount, onConfirm }) => {
  return (
    <div className="payment-container">
      <h3>支付 ¥{amount}</h3>
      <button onClick={onConfirm}>确认支付</button>
    </div>
  );
};

改写成Web Component后:

class PaymentWidget extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    
    const amount = this.getAttribute('amount');
    this.shadowRoot.innerHTML = `
      <style>
        .container { padding: 16px; border: 1px solid #eee; }
        button { background: #007bff; color: white; border: none; }
      </style>
      <div class="container">
        <h3>支付 ¥${amount}</h3>
        <button id="confirm">确认支付</button>
      </div>
    `;
    
    this.shadowRoot.getElementById('confirm')
      .addEventListener('click', () => {
        this.dispatchEvent(new CustomEvent('confirm', { detail: { amount } }));
      });
  }
}

customElements.define('payment-widget', PaymentWidget);

使用起来也简单得离谱:

<!-- 在任何页面直接使用 -->
<payment-widget amount="99.99" @confirm="handleConfirm"></payment-widget>

连React项目里都能直接塞进去,完全不用管它内部是啥。上周五上线时,测试同学居然没找我茬——这在我司可是稀有事件!

和React比,到底谁更香?

我知道很多前端朋友会问:现在React生态这么成熟,干嘛还要折腾Web Components?作为半个后端,我从几个实际角度对比了一下:

维度 Web Components React
依赖 无(浏览器原生) 需打包react/react-dom
体积 ~0KB(仅业务代码) 至少40KB+
跨框架 完美支持 需桥接或重写
开发体验 原生JS,调试直接 JSX + Hooks,生态丰富
安全性 Shadow DOM天然隔离 依赖CSP等额外措施
学习成本 对后端友好 前端专属概念多

在我们这种对安全审计极其严格的环境里,Web Components的“零依赖”特性太重要了。每次引入一个新npm包,都要过三道安全扫描,有时候一个小工具拖慢整个上线流程。而原生组件,浏览器就是它的运行时,连package.json都不用改。

工具链:别被“原生”骗了

虽然叫“原生”,但真要投入生产,还是得靠工具提效。我试了几个主流方案:

  • Lit:Google出品,轻量级(<5KB),带响应式更新,写起来有点像精简版React
  • Stencil:Ionic团队开发,支持TSX,还能编译出多种框架的适配器
  • Vanilla:纯手写,适合极简场景

最后我们选了Lit,因为它在保持轻量的同时,提供了类似useState的@state装饰器,写起来舒服很多:

import { LitElement, html, css } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';

@customElement('secure-payment')
export class SecurePayment extends LitElement {
  @property({ type: Number }) amount = 0;
  @state() isLoading = false;

  static styles = css`
    .btn { /* ... */ }
  `;

  render() {
    return html`
      <div>
        <h3>支付 ¥${this.amount}</h3>
        <button 
          @click=${this._confirm}
          ?disabled=${this.isLoading}
          class="btn"
        >
          ${this.isLoading ? '处理中...' : '确认支付'}
        </button>
      </div>
    `;
  }

  private async _confirm() {
    this.isLoading = true;
    // 调用安全支付接口
    this.isLoading = false;
  }
}

兼容性与性能:别踩坑

当然,天下没有免费的午餐。Web Components在IE上基本歇菜(但我们早就不支持IE了),Safari的早期版本也有坑。好在现在Can I Use显示,主流浏览器支持率已超95%。

性能方面,我做了个简单压测:在同一个页面渲染100个组件实例。

  • React(v18):平均渲染时间 120ms
  • Web Components(Lit):平均渲染时间 95ms
  • 纯原生(无框架):平均渲染时间 85ms

虽然差距不大,但在我们这种高频交易场景下,每毫秒都可能影响用户体验。更关键的是,Web Components的内存占用明显更低——这对移动端尤其重要。

综合来看,它不是替代品,而是补充

写到这里,我必须澄清一点:Web Components 不是要取代React,而是提供了一种新的可能性。在我们的技术栈中,现在是这样分工的:

  • 主应用:继续用React,享受其强大的生态和开发体验
  • 跨平台微组件:如支付、身份验证、风险提示等,用Web Components封装
  • 第三方集成:给合作伙伴提供的嵌入式组件,全部基于Web Components

这种混合模式,既保留了React的开发效率,又解决了跨框架复用的痛点。上周和前端组开会,他们居然主动要求把几个通用UI组件也改造成Web Components——看来真香定律无人能挡。

结语:后端视角看前端演进

作为一个常年和分布式系统打交道的后端,我越来越觉得,前端的“微前端”、“组件化”思路,其实和后端的微服务、模块化异曲同工。Web Components就像前端世界的gRPC——定义清晰的接口,语言无关,随处可嵌。

最近在考虑跳槽,面试时聊到这个实践,好几个技术负责人眼睛都亮了。看来,掌握这种“跨界”能力,在当前环境下确实是个加分项。

如果你也在被跨框架复用折磨,或者像我一样,是个被逼学前端的后端,不妨试试Web Components。它可能不会让你成为React高手,但绝对能帮你少加几次班——毕竟,能用原生解决的问题,何必再拉一堆依赖呢?

(完)

P.S. 刚才测试又来找我,说Safari上按钮样式有点歪……算了,先去改CSS,咖啡续命!

评论 0

最热最新
暂无评论
云端行者Lv.1
0
影响力
0
文章
0
粉丝