logo
Published on

Web component series — server-side rendering(SSR) solution

Authors

Web component series —— server-side rendering(SSR) solution

  • Note: This series mainly discusses the concepts and pain points of web components, aiming to help readers better understand the advantages and pain points of web components.

Preface

SSR (server side rendering) is very common in our front-end development. It mainly appears because we have the following requirements:

SEO optimization, we hope that crawlers can also obtain our complete web page information when crawling pages. If the user disables js, our web pages should also run normally Web page performance LCP and other core web page indicators optimization

The web components we implemented in the previous sections are all imperative programming methods, such as:

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

This operation can only be used in CSR (client side rendering),

which will cause our page to have a white screen for a certain period of time and possible jitter.

These pain points of web components are the reason why we need to introduce a new declarative command - declarative-shadow-dom

Declarative shadow-dom

We introduced the element in the previous chapter.

When the browser parses it, it will be ignored by default.

Our declarative shadow-dom is a template element with a shadowrootmode attribute, which is implemented as follows:

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

If We Run it in the website, you will find declarative shadow-dom is too slow!!!

Obviously, this is very different from the page we actually want to present to the user,

and it is obviously lagging behind in LCP and SEO search, which is why we use declarative-shadow-dom!

Compatible with declarative shadow DOM

When we may not be compatible with declarative shadow dom in some browsers,

the compatible way is to write a polyfill ourselves.

The general idea is to attach each child element with template shadow root mode attribute to our corresponding parent element through 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

Previously, we just mounted the relevant static elements on the page.

If we want this component to be interactive and the user's operation can change the corresponding state,

how can we implement the hydration of web components?

<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>

Summary​

Web components technology is still under development.

Once our project requirements change, it may be difficult to find corresponding solutions as quickly as Vue and React to meet our production needs.

The natural isolation brought by web components is actually implemented in major mainstream frameworks and works well.

Maybe we don’t need web components at all?

However, considering the following scenarios, I think web components are still worth considering:

  1. Common components across pages, such as some navigation tools, pop-ups, etc.

  2. Web components can be used when different teams use different frameworks across teams.

  3. Cross-project, many times we are faced with the maintenance and update of old projects, and embedding web components is a good choice.

Reference

Github——Declarative Shadow DOM feature development: https://github.com/mfreed7/declarative-shadow-dom

HTML Standard: https://html.spec.whatwg.org/multipage/scripting.html#attr-template-shadowrootmode

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