简单记录 WebComponent SSR 的实现,以及使用 lit hydrate 的来做客户端 patch.

Template shadowroot

WebComponents 的 SSR 基本原理是通过 template shadowroot 属性实现的。

<my-element>
  <template shadowroot="open" shadowrootmode="open">
    <style>* { color: #f00; }</style>
    <div>hello world</div>
  </template>
</my-element>

以上代码,template 会被 clone 并 attch 到新建的 shadowdom 上。

image

在线 Demo:https://systemjs.1688.com/krump/schema/2442.html

Lit Component

编写 my-element-ssr 组件。

import { LitElement, html, unsafeCSS } from 'lit'
import { customElement, state } from 'lit/decorators.js'

@customElement('my-element-ssr')
class MyElement extends LitElement {
  static styles = unsafeCSS('* { color: red; }')

  @state({ type: Number })
  accessor count = 0;

  click () {
    this.count++
  }

  render () {
    return html`<div>hello world</div><button @click=${this.click}>count ${this.count}</button>`;
  }
}

使用 rollup.config.js 将部分 decorator、accesser 做兼容处理。

最终打成一个 ESM 兼容模块,element.js

Lit SSR

参考 lit-ssr

import {render} from '@lit-labs/ssr';
import {collectResultSync} from '@lit-labs/ssr/lib/render-result.js';

const result = render(html`<my-element-ssr></my-element-ssr>`);
// Throws if `result` contains a Promise!
const html = collectResultSync(result);

得到 html SSR 后的代码如下:

<my-element-ssr>
  <template shadowroot="open" shadowrootmode="open">
    <style>* { color: red; }</style>
    <!--lit-part zwZEgz88vW4=-->
      <!--SSR 后里面的内容可以再次修改,后续的比对是组件内的模板 strings 和上面的这个 digest -->
    <div>hello world</div>
      <!--lit-node 1-->
      <button >
        count
        <!--lit-part-->0<!--/lit-part-->
      </button>
    <!--/lit-part-->
    </template>
</my-element-ssr>

Lit Hydrate

Hydrate 原理是通过对 template 做 digest 并 patch SSR 结果上。

digest 后的内容类似 <!--lit-part zwZEgz88vW4=-->, SSR 的结果会和当前 client 组件的 template strings 做对比。如果对比成功,就走 patch 逻辑,如果对比失败,就会做 append 逻辑。

digest 的代码实现:digestForTemplateResult

在线 Demo https://systemjs.1688.com/krump/schema/2444.html

兼容 chrome 70

entry 代码

import { hasNativeDeclarativeShadowRoots, hydrateShadowRoots, } from '@webcomponents/template-shadowroot/template-shadowroot.js';
import { LitElement } from 'lit'


if (!hasNativeDeclarativeShadowRoots()) {
  hydrateShadowRoots(document.body);
}


import('@lit-labs/ssr-client/lit-element-hydrate-support.js').then(
  () => {
    window.litElementHydrateSupport({ LitElement })
    import('./element.js');
  }
)

Vite 配置,并做打包构建 vite.config.js

在线 Demo

React SSR with WebComponent

  • https://systemjs.1688.com/krump/schema/2451.html