As I mentioned in my last post, I really wanted to find a Web Component library that builds, you know, Web Components. Each component should be a standalone, loadable file ending in .js that instantiated the constructor of a fully-realized web component. I wanted a few bells and whistles, like HTML and CSS auto-templating, Typescript is a must but Sass is a nice-to-have.

Stencil promised that. It's promise reads "Stencil is a library for generating small, blazing fast Web Components that run everywhere." I'm took them at their word.

They lied.

Stencil even provides a build target, www, which promises to build a reusable component library. And like a real library, like the kind from which you check out books, I shouldn't need anything more than the book or the component in order to accomplish my task. For each web component I define, there should ultimately be one and only one file with everything it needs.

I checked out the Stencil v3.0 "Hello World" application, and I built it, and then I checked the output. Here's what I found1:

$ find . -name '*.js' -type f -print0 | xargs -0 grep -E '^import|Hello, World!' | cut -c1-80
./dist/collection/components/my-component/my-component.js:import { format } from
./dist/collection/components/my-component/my-component.js:    return h("div", nu
./dist/components/my-component.js:import { proxyCustomElement, HTMLElement, h } 
./dist/components/my-component.js:    return h("div", null, "Hello, World! I'm "
./dist/esm/my-component.entry.js:import { r as registerInstance, h } from './ind
./dist/esm/my-component.entry.js:    return h("div", null, "Hello, World! I'm ",
./dist/stencil-starter-project-name/p-2329c98e.entry.js:import{r as t,h as n}fro
./www/build/p-2329c98e.entry.js:import{r as t,h as n}from"./p-0150615e.js";funct

Each and every file with the phrase "Hello, World!" in it also has an import statement, which means that every supposedly "standalone component" needs to pull in some sort of external dependency in order to truly work. That's not standalone.

I expect a Web Component library to spit out a Web Component, a standalone JavaScript object that can be pulled in. I don't even care if the build system has to package a little bit of runtime with each and every component, I just really, truly want them each to be really, truly standalone.

Bizarrely enough, for all my complaints about Lit, I have a working bundler configuration for standalone Web Components using Lit and Vite. I'm not ecstatic that a 5.2KB Web Component bundles to 32KB of JavaScript after Vite has bundled it all together, but at least it does what I want. 27KB of overhead is a lot more than "a little bit of runtime," since most components are going to be small and targeted, and I'd hoped for better from Stencil.

I'm really tired. I loved programming because, if I was smart enough, I could make the computer do exactly what I wanted. This alchemical mixing and blending of configurations and plugins and environments until it kinda-sorta-maybe does what you expected is not what I signed up for.


1 Truth be told, the bash script I actually used is much more, er, complex:
$ (find . -name '*.js' -type f -print0 | xargs -0 grep 'Hello, World!' ; \
   grep -m 1 '^import' $(find . -name '*.js' -type f -print0 | \
   xargs -0 grep -l 'Hello, World!')) | \
   sort | \
   cut -c1-80

Which is "Find all the files with 'Hello, World', and then rescan all those files for at least one import statement, then sort them so the import and 'Hello' are in order and so the results are proximate."