Big W for Web Components

Issue #326.September 26, 2024.2 Minute read.
Bytes

Today’s issue: Proving myself to the Home Depot employees, pretending to learn Vim, and holding our elected officials responsible for how my React app renders.

Welcome to #326.


Eyeballs logo

The Main Thing

Mark Zuckerb

When you look too deep into the Shadow DOM

Big W for Web Components

As we head into election season, there’s one particularly polarizing topic I recommend avoiding if you don’t want to fight with strangers on the internet: Web Components.

That’s (mostly) a joke, but we’re breaking that rule today to cover some big news in WC world – every major browser now supports SSR, thanks to Jason Miller and Mason Freed’s work on Declarative Shadow DOM.

Quick review: If you don’t regularly work with Web Components, the term “Shadow DOM” might sound a little more kinky than the topics we normally cover. But fortunately (or unfortunately?), Shadow DOM is simply a part of the Web Components spec that provides a way to scope CSS styles to a specific DOM subtree, then isolate that subtree from the rest of the document.

This lets you create reusable elements without worrying about style or script conflicts. A basic example might look something like this:

<menu-toggle>Open Menu</menu-toggle>
<script>
  class MenuToggle extends HTMLElement {
    constructor() {
      super();
      const shadow = this.attachShadow({ mode: "open" });
      shadow.innerHTML = `
        <style>
          button {
            background: blue;
            color: white;
          }
        </style>
        <button>
         <slot></slot>
        </button>
      `;
      shadow.firstChild.addEventListener("click", () => {
        // toggle the menu
      });
    }
  }

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

The problem was that this API only worked on the client, which meant it lost many of the benefits of SSR. To work around this, the team added a new spec called “Declarative Shadow DOM.” It uses the template API in order to provide the initial markup, like this:

<menu-toggle>
  <template shadowrootmode="open">
    <style>
      button {
        background: blue;
        color: white;
      }
    </style>
    <button>
      <slot></slot>
    </button>
  </template>
  Open Menu
</menu-toggle>
<script>
  class MenuToggle extends HTMLElement {
    constructor() {
      super();
    }

    connectedCallback() {
      const button = this.shadowRoot.querySelector("button");
      button.addEventListener("click", () => {
        // toggle the menu
      });
    }
  }
  customElements.define("menu-toggle", MenuToggle);
</script>

In addition to improving the SEO story, DS DOM also enables streaming rendering and prevents flashes of unstyled content (FOUC), because the styles are present on the initial page load.

Bottom Line: Historically, one of the biggest drawbacks to using Web Components has been the lack of support for SSR – so unlocking full browser support for Declarative Shadow DOM is a big step forward.

        

expo logo

Our Friends
(With Benefits)

Shaggy from Scooby Doo squinting

When you push a bug to prod then have to wait 5-7 days for app store approval to fix it

CodePush is getting deprecated in March 👀

And that means you’ll probably need a new way to do over-the-air updates for your mobile app.

That’s why lots of teams are trying out EAS Update – Expo’s flexible tool for delivering bug fixes, new content, and other OTA updates to your users.

We all know that Expo-the-framework provides the best DX for building React Native apps, and EAS Update does the same thing for OTA updates. Here’s how:

  • It offers feature rollouts and rollbacks for safer releases, plus a simple dashboard that lets you track the status of all updates.

  • It provides a republish command that lets you immediately republish a previous, stable version if there’s an issue with a new release.

  • It seamlessly handles all scalability and maintenance issues for you.

The best part: Expo heard everyone’s complaining constructive feedback about EAS Update being too expensive – so they just dramatically reduced their pricing to make it more manageable for teams of any size.

Check out the docs to get started.


Pop Quiz logo

Pop Quiz

Spot the Bug – Presented by Snyk

Join Roman Lavrik from Deloitte and hundreds of other security experts at DevSecCon 2024 to gain valuable insights about securing your enterprise in the AI age.

What gets logged?

const array = new Array(3).fill([])
array[0].push("bytes")
console.log(array)

Cool Bits logo

Cool Bits

  1. Have you ever wondered how React Query keeps its data in sync with the server? No…? Oh, well we wrote this wonderful piece on how that happens anyway.

  2. Josh Goldberg wrote about why typed linting needs TypeScript today. For some reason, the last dinner party I went to wasn’t impressed when I spent 15 minutes monologuing on the same topic.

  3. Cameron Pavey and Dan Moore wrote about how to avoid authentication system lock-in when using a third-party auth platform like FusionAuth. [sponsored]

  4. Leerob made a free mini-course called Vim for React Developers. Guaranteed to finally earn you the respect of your peers, or your money back.

  5. Nolan Lawson wrote about improving rendering performance with CSS content-visibility.

  6. Everything in the WordPress ecosystem is totally normal and not on fire at all right now. Not.

  7. Lindsay Piper wrote about how to optimize JavaScript bundle sizes using Codecov’s bundle analysis tool, so you can cut down your JS bloat for good. [sponsored]

  8. Jim Nielsen wrote about sanding down your UI – which proves that there might be at least one thing I can teach the Home Depot workers that they don’t already know.

  9. Ahmad Shadeed wrote an in-depth case study about how he redesigned his personal website.

  10. Sunil Pai wrote an article called Partial prerendering for everyone with Cloudflare Workers. I just hope he makes good on this campaign promise once he gets elected President of PPR. Remember the little people like us who got you there, Sunil.


Pop Quiz logo

Pop Quiz: Answer

What gets logged?

const array = new Array(3).fill([])
array[0].push("bytes")
console.log(array) // [ ["bytes"], ["bytes"], ["bytes"] ]

The key to understanding this one is in knowing that arrays in JavaScript are reference values.

When you call .fill([]), what you’re really doing is “filling up” the array with three references to the same array. You can kind of think of it like this.

const reference = []
const array = new Array(3).fill(reference)

Where now, array has three elements and they’re all referencing the same reference array. Therefore, if you add an item to any of the three elements, since they all point to the same array, it’s as if you’re adding an item to all of them.

To get the same functionality without the referential weirdness, you can use Array.from.

const array = Array.from({ length: 3 }, () => []);
array[0].push("bytes");  // [ ["bytes"], [], [] ]