Adding Components to Eleventy with WebC

Components have been an often requested feature in Eleventy. While I do consider it an unanswered question whether or not components are the best starting point for new developers, it’s hard to argue with the efficiency and delivery gains to be had…


This content originally appeared on Zach Leatherman and was authored by Zach Leatherman

Components have been an often requested feature in Eleventy. While I do consider it an unanswered question whether or not components are the best starting point for new developers, it’s hard to argue with the efficiency and delivery gains to be had for folks with a bit more experience.

Now, we could wait around for the heavier bundler-based frameworks to circle back and pretend like React server components are a revolutionary new pattern for HTML without JavaScript (can you imagine). But if I might be allowed to offer a well-argued and intellectually-bulletproof counterpoint: naw.

A History of Component-like Things

Historically, Eleventy has offered a few component-like features. Before we move on, I think it’s worthwhile to go through the prior art here (for Eleventy specifically).

  1. Liquid Render {% render %} tag, the successor to the deprecated Liquid Include {% include %} tag.
  2. Nunjucks Include {% include %} tag
  3. Nunjucks Macro (and Import)
  4. Eleventy Shortcodes (both single and paired)
  5. Eleventy Render Plugin

Shortcodes (and the Render plugin) were close to the developer experience folks expect from a component system, but they have their own drawbacks.

  • Some template languages were good at handling asynchronous behavior by default (Liquid) and others required awkward delineation between asynchronous and synchronous behavior (Nunjucks).
  • You can’t invoke other shortcodes from inside of a shortcode definition (the JS function in your Eleventy configuration file). You can nest shortcodes in paired shortcode content but that isn’t always enough.

Shortcodes are okay. We can do better.

The Age of Vue + Eleventy

Shipped in 2020 to support a netlify.com tech stack move to Eleventy, the Eleventy Vue SFC plugin was the first big foray into full first-party components for Eleventy. This used Vue single file components and rendered them to plain-’ol HTML (without shipping any client JavaScript).

Vue components are great! Here are a few things I loved:

  • Single file component authoring nicely co-locates HTML, CSS, and (for this plugin at least) server-only JavaScript.
  • Vue components felt more like authoring HTML (not JavaScript for everything).
  • Vue merges class and style attributes smartly between host components and component definitions. I know it’s a little thing but this felt like a huge authoring win when your component is HTML-aware (which shortcodes are not).
  • Using the is attribute to redefine components inline
  • Using attribute bindings for scripting attribute values.
  • Vue SFCs also offer CSS scoping built-in, although in practice I didn’t use it much! I liked to have more descriptive classes for components I build.
  • The Eleventy Vue plugin also generated per page CSS bundles and brought first-class incremental builds to Eleventy Vue projects (not all template languages in Eleventy support incremental builds).

Maintenance Woes

The biggest drawback of this approach was that the Eleventy Vue plugin uses rollup-plugin-vue which—perhaps obviously—is tightly coupled to the Rollup bundler! I’ve talked a bit about the long term risk of coupling to an official bundler in Eleventy, and those certainly played out with some prescient accuracy here.

Vue 3 was released (beta in April 2020, stable in September 2020) after the Eleventy Vue plugin and an official Vue 3 rollup-plugin-vue@6.0.0 was released in November 2020. Notably, this was happening at the same time as a rapid rise in popularity for Vite. Accordingly, the rollup-plugin-vue repo is now archived and not maintained and folks are recommended to use Vite instead of the rollup plugin for Vue compilation.

Unfortunately, due to Vue’s upstream moves here, we’ll likely end up archiving eleventy-plugin-vue too.

Web Components

Building netlify.com with server-rendered zero-bundle Vue components was a great experience but interestingly we didn’t ship any client-side Vue components on the site (during my tenure). For interactivity we were leaning on Web Components (mostly Custom Elements), which offered a very similar zero-overhead mentality in the client-side world.

When you talk about web components publicly, it’s almost certain that you’ll get a helpful link to a 2019 blog post from Rich Harris (the creator of Svelte) titled Why I don’t use web components. The post has has some valid criticism (though it leans kinda hard into complaints about Shadow DOM, that I quickly realized was an optional feature and conveniently ignored it 😅 for technical reasons that are outside the scope of this post).

But Rich’s top issue in the post is Progressive Enhancement. Yes, lots to agree on there. Rich starts his argument with the point that he can write a Svelte component that spits out server-rendered HTML like this:

<a target="_blank" noreferrer href="" class="svelte-1jnfxx">
Tweet this
</a>

…and in this Rich compares Svelte’s server-rendered HTML to a client-rendered Web Component:

<twitter-share text="" url="" via=""/>

Apples to oranges aside, this is a good distillation of the expectations mismatch for a lot of folks. If you’re coming over from a framework component background, you likely expect first-class server rendering for Web Components to be solved by the platform.

To put it succinctly, developers want to write <twitter-share text="…" url="…" via="…"> and have browsers serve <a target="_blank" noreferrer href="…">Tweet this</a> without a build or compile step.

Well, you can’t. But JavaScript component frameworks can’t do this either.

Going back to Rich’s example, I would say that the ideal client-rendered web component markup would look something like this:

<twitter-share>
<a href="">Tweet this</a>
</twitter-share>

…and the component might transform the markup to add the component attributes as needed, maybe to render something like this:

<twitter-share>
<a href="" target="_blank" noreferrer>Tweet this</a>
</twitter-share>

Notably, any time you modify the DOM with JavaScript it creates a tension point for progressive enhancement. Is it okay that before-JS or broken-JS users won’t have those attributes added to the link? Maybe for this use case. But for more complex components, these tradeoff decisions cannot be made universally. They must be made by the web authors with the full context of the use case for the project they are working on.

(Side note that this is why component-based design systems have a hard time—components don’t have the individual use-case specific context necessary to make judgement calls and can only advise on how they might be used in more broader, generic use cases)

It isn’t a level playing field to compare server-rendered framework components to client-rendered web components but it does highlight the need for additional Web Component tooling to deliver the maximum amount of code re-use with the minimum amount of tradeoff. Let’s add a build/compile/server render step for Web Components—my biased suggestion is to use WebC!

The Age of WebC + Eleventy

WebC is a framework-independent standalone HTML compiler for generating markup for web components.

When creating WebC, I wanted to bring all of the good things from Vue’s single file components to Web Components: HTML-first single file component authoring, class and style attribute merging, webc:is (instead of is to avoid attribute collisions), dynamic attributes using the : prefix, scoped CSS, per-page CSS and JS bundles, and fully incremental builds.

On top of those, WebC offers full access to the Data Cascade inside of your components, is 100% async friendly, designed as a server-first tool (rather than a client-first retrofit), offers zero-overhead client interactivity (requires no library code), is streaming friendly, is not coupled to a bundler and includes some bundler functionality built-in, and is extensible with other template language syntax (Markdown, Nunjucks, Liquid, Sass, etc).

Here are a few links to get started with WebC:

What’s Next for WebC?

  1. More integrations! I loved to see an Express plugin for WebC from Nick Colley and a Vite plugin for WebC from @mayank99
  2. HTML bucketing! We already have CSS/JS asset aggregation. I’d like to see this with arbitrary HTML too. Think of a single WebC component file for a web font that includes both the @font-face CSS and the preload HTML together! Or a WebC icon that only includes a single <g> that aggregates up to a reusable de-duplicated SVG icon set.
  3. Writing asset bundles to files (now we’re really getting into bundler-functionality)
  4. Aliases for node_modules so you can import easily from npm! Folks can publish a webc file for re-use in any other project (that also includes the HTML, JS, and CSS) to use directly.
  5. More sugar for loops/conditional rendering. Those this is possible using template syntax or JavaScript render functions now, it could be less verbose!
  6. Tighter integration with <is-land>: I’d like to see us get to the point where WebC components will be able to declare assets to load conditionally based on <is-land> loading conditions. Super granular control and power!

The best way to keep up to date here is to subscribe to our YouTube channel or follow us on Twitter!

Thanks, y’all!


This content originally appeared on Zach Leatherman and was authored by Zach Leatherman


Print Share Comment Cite Upload Translate Updates
APA

Zach Leatherman | Sciencx (2022-10-06T00:00:00+00:00) Adding Components to Eleventy with WebC. Retrieved from https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/

MLA
" » Adding Components to Eleventy with WebC." Zach Leatherman | Sciencx - Thursday October 6, 2022, https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/
HARVARD
Zach Leatherman | Sciencx Thursday October 6, 2022 » Adding Components to Eleventy with WebC., viewed ,<https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/>
VANCOUVER
Zach Leatherman | Sciencx - » Adding Components to Eleventy with WebC. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/
CHICAGO
" » Adding Components to Eleventy with WebC." Zach Leatherman | Sciencx - Accessed . https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/
IEEE
" » Adding Components to Eleventy with WebC." Zach Leatherman | Sciencx [Online]. Available: https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/. [Accessed: ]
rf:citation
» Adding Components to Eleventy with WebC | Zach Leatherman | Sciencx | https://www.scien.cx/2022/10/06/adding-components-to-eleventy-with-webc/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.