你不知道的web component系列——服务端渲染SSR方案

注: 本系列主要是探讨web components的概念和使用痛点, 旨在让读者更加了解web components的优势和痛点, 系列参考:

  1. 你不知道的web component系列——改造Vite模版实现一个自定义元素
  2. 你不知道的web component系列——改造Vite模版了解shadowDom和插槽-CSDN博客

前言

SSR(server side rendering)对于我们前端开发是非常常见的,它的出现主要是因为我们有着下面的需求:

  1. SEO优化, 我们希望爬虫在抓取页面的时候也可以获取到我们完整的网页信息,如果在用户禁用js的情况下, 我们的网页应该也可以正常运行
  2. 网页页面性能LCP等核心网页指标优化

而我们前面几节实现的web component都是命令式的编程方式, 比如:

const goalEl = document.getElementById('goal')
const shadowRoot = goalEl.attachShadow({mode: 'open'})
shadowRoot.innerHTML = '<h1>Hello World!</h1>';

这样的操作只能在CSR(client side rendering)中使用, 这样会导致我们的页面会有一定时间的白屏以及可能的抖动,这些web components存在的痛点都是我们要引入新的声明式命令的原因——declarative-shadow-dom

声明式shadow-dom

我们在前面章节有介绍到<template></template>这个元素, 当浏览器解析到它时就会默认忽略, 而我们的声明式shadow-dom就是一个有着shadowrootmode属性的template元素,实现如下:

<host-element>
  <template shadowrootmode="open">
    <slot></slot>
  </template>
  <h2>Light content</h2>
</host-element>

因为vite本身会在本地跑起一个服务器, 因此我们只需要打开浏览器查看网络状态栏(为了更好的对比差异, 我们打开3g的过滤选项):

显然这和我们实际想要呈现给用户的页面差异很大,并且在LCP和SEO搜索上显然是落后的,这也是我们为什么要使用declarative-shadow-dom的原因!

兼容declarative shadow dom

当我们在某些浏览器中可能不兼容declarative shadow dom, 兼容的方式就是我们自己写一个polyfill,大致思路是把每一个具有template shadow root mode属性的子元素通过appendChild的方式挂载到我们对应的父元素身上:

(function attachShadowRoots(root) {
  root.querySelectorAll("template[shadowrootmode]").forEach(template => {
    const mode = template.getAttribute("shadowrootmode");
    const shadowRoot = template.parentNode.attachShadow({ mode });

    shadowRoot.appendChild(template.content);
    template.remove();
    attachShadowRoots(shadowRoot);
  });
})(document);

水合(Hydration)

前面我们只是挂载了相关的静态元素到页面上, 如果我们希望这个组件是一个交互式的, 用户的操作可以改变对应的状态, 该如何实现web components的hydrate尼?

<menu-toggle>
  <template shadowrootmode="open">
    <button>
      <slot></slot>
    </button>
  </template>
  Open Menu
</menu-toggle>
<script>
  class MenuToggle extends HTMLElement {
  constructor() {
    super();

    const internals = this.attachInternals();

		// 用于判断是否使用了declarative shadow dom
    let shadow = internals.shadowRoot;

    if (!shadow) {
      shadow = this.attachShadow({
        mode: 'open'
      });
      shadow.innerHTML = `<button><slot></slot></button>`;
    }
    shadow.firstChild.addEventListener('click', toggle);
  }
}

customElements.define('menu-toggle', MenuToggle);
</script>

总结

web components技术现在还是处于发展中, 很多的功能一旦我们的项目需求发生改变, 可能很难向Vue,React那样快速的找到对应的解决方案并达到我们的生产需求, web components所带来的天然性隔离其实在各大主流的框架中也都有实现并且效果不错, 也许我们根本用不到web components?

但是,考虑到下面的场景, 笔者认为 web components还是很值得去考虑的:

  1. 跨页面的公用组件, 比如一些导航工具, 弹窗等等
  2. 跨团队,不同的团队使用的不同框架时就可以使用web components来适用.
  3. 跨项目, 很多时候我们都面临着对老旧项目的维护和更新, web components来嵌入就是一个不错的选择.

参考

GitHub - mfreed7/declarative-shadow-dom: Declarative Shadow DOM feature development

HTML Standard

https://web.dev/articles/declarative-shadow-dom?hl=zh-cn

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值