Web Components:原生组件化开发新趋势?别被面试题忽悠瘸了

开发者小宇宙
2026-03-19 01:50
阅读 1699

上周五晚上11点,我瘫在出租屋的破沙发上,手里捏着刚泡好的老坛酸菜面,屏幕还亮着——老婆发来消息:“今天又加班到这么晚?你不是说入职后能准时下班吗?”
我苦笑一下,回了个“项目赶上线,明天见面再说”,然后默默关掉微信。房租3500、通勤一小时、异地恋……这大厂offer(月薪从15k涨到22k)拿得真不轻松。

但更让我头疼的,是今天白天组里那个技术选型会。


事情得从去年十月说起。那时候我还在投简历,每天刷LeetCode、背八股文,做梦都在答“React和Vue的区别是什么”。某天晚上和老婆视频,她突然问我:“你最近怎么老提Web Components?是不是又学新东西了?”
我说:“唉,不是我想学,是面试官问的!上周面字节,一个前端主管直接甩我一道题:‘如果不用框架,怎么实现组件化?’ 我支支吾吾说了Shadow DOM,他立马追问Web Components的兼容性和性能瓶颈……”

那场面试我没过。但Web Components这个词,从此在我脑子里扎了根。


Fast forward到今年三月,我终于拿到这家一线大厂的offer。入职第一周,组长就丢给我一个“创新实验项目”:用纯原生技术栈重构一个内部工具面板,要求不依赖React/Vue/Angular,还要支持微前端集成。

“试试Web Components吧,”他说,“最近Prompt工程火得很,我们想搞个低代码平台,让非前端也能拖拽生成UI模块。Llama和Kimi都能写基础组件了,但底层还是得靠标准。”

我当时心里咯噔一下:这不就是把面试题变成生产任务了吗?


于是,我开始了为期两周的“Web Components实战地狱”。

先说结论:Web Components确实是原生组件化的未来方向,但它现在的生态,就像我租的这间房——便宜、原生、但没热水没WiFi还得自己修马桶。

技术选型对比:理想很丰满,现实很骨感

我横向对比了三种方案:

1. 传统框架(React/Vue)

  • 优点:开箱即用,生态成熟,连我老婆都知道Vue双向绑定香。
  • 缺点:体积大,打包慢,微前端场景下容易版本冲突。而且——不符合老板“去框架化”的政治正确

2. Web Components(原生)

  • 优点:浏览器原生支持(Chrome/Firefox/Edge基本OK),零依赖,天然隔离(多亏Shadow DOM),和任何框架都能共存。
  • 缺点:写起来像回到jQuery时代。没有响应式数据绑定(得自己监听attributeChangedCallback),事件系统原始,调试困难,SSR基本放弃治疗。

3. Web Components + 轻量库(Lit / Stencil)

  • 优点:保留原生优势的同时,加了响应式、模板语法、TypeScript支持。Lit尤其轻(<5kb),Google亲儿子。
  • 缺点:又要引入第三方库,违背了“纯原生”的初心;团队学习成本依然存在。

最后我选了Lit + 原生Web Components混合模式。为啥?因为纯手写Web Components真的会死人。

举个栗子:我想做个带状态的按钮组件。
用React:

const MyButton = ({ loading, onClick }) => (
  <button disabled={loading} onClick={onClick}>
    {loading ? 'Loading...' : 'Click me'}
  </button>
);

用原生Web Components:

class MyButton extends HTMLElement {
  static get observedAttributes() { return ['loading']; }
  
  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.render();
  }

  attributeChangedCallback(name, oldValue, newValue) {
    if (name === 'loading') this.render();
  }

  render() {
    const loading = this.hasAttribute('loading');
    this.shadowRoot.innerHTML = `
      <button ${loading ? 'disabled' : ''}>
        ${loading ? 'Loading...' : 'Click me'}
      </button>
    `;
  }
}
customElements.define('my-button', MyButton);

看到没?八行变三十行,还不能自动更新状态。要是再加个点击事件,你还得在render里手动addEventListener,还得防内存泄漏……

那一刻我真想对着屏幕喊:“面试官,你当年问我Web Components的时候,试过自己写一个完整的表单吗?”


Prompt工程救不了你,但能帮你少踩坑

不过话说回来,现在AI确实帮了大忙。上周我让Kimi生成一个带验证的输入框组件,它居然把attributeChangedCallback和formAssociated都写对了(虽然忘了加disconnectedCallback清理事件)。
我又用Llama 3本地跑了个prompt:“Write a Web Component for a date picker with i18n support”,结果生成的代码虽然不能直接用,但结构清晰,省了我查MDN半小时。

所以别信什么“AI取代程序员”——它顶多帮你把八股文答案翻译成能跑的代码,但架构决策、性能优化、边界case处理,还得靠你自己熬通宵。


异地+加班,我为什么还在坚持?

老婆上周问我:“你们公司非要用这种冷门技术,值得吗?”
我说:“短期看不值得,长期看可能是押注。”

Web Components最大的价值不是“不用框架”,而是跨技术栈复用。我们内部有React、Vue、Angular三个团队,每次做通用组件都要重复造轮子。如果全用Web Components封装,一次开发,到处使用——这才是微前端的终极解法。

而且,浏览器原生的东西,永远不会被淘汰。React可能五年后没人用了,但customElements.define()只要W3C不倒,就能跑。

当然,现实很残酷:IE?拜拜了您。Safari?部分特性滞后。SSR?自己想办法。测试?Jest不友好,得上Playwright。

但这就是技术人的宿命:在理想和妥协之间找平衡点


给后来者的建议

如果你也在准备面试,遇到“Web Components vs 框架”这类题,别只会背概念。可以这样说:

“Web Components适合做底层原子组件跨框架共享模块,比如Design System里的Button、Modal。但复杂业务逻辑还是交给React/Vue,它们的状态管理和开发体验不可替代。两者不是替代关系,而是分层协作。”

如果你已经在项目里用它——
千万别裸写!上Lit或Stencil,不然你会在attribute和property的转换中怀疑人生。


最后一点私心话

写这篇文章时,已经是凌晨1点。明天终于能见到老婆了,她说要带我去吃那家我念叨三个月的潮汕牛肉锅。
我看着屏幕上还在报错的custom element,突然觉得:技术也好,感情也罢,哪有什么完美方案?都是在限制条件下,尽量不让自己后悔的选择。

Web Components或许不是银弹,但它代表了一种可能性——回归标准,拥抱开放,减少依赖。在这个前端框架月抛的时代,这份“笨拙的坚持”,反而显得珍贵。

就像我和老婆的异地恋:没有花哨的技巧,只有每周五晚上的高铁票,和一句“我在站台等你”。

技术如此,生活亦如此。


P.S. 如果你也在折腾Web Components,欢迎留言交流。别一个人硬扛,我们前端人,得互相取暖。

评论 0

最热最新
暂无评论
开发者小宇宙Lv.1
0
影响力
0
文章
0
粉丝