npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@11ty/webc

v0.11.4

Published

Single File Web Components

Downloads

8,290

Readme

WebC is for Single File Web Components

Features

  • Framework-independent standalone HTML serializer for generating markup for Web Components.
    • Expand any HTML element (including custom elements and web components) to HTML with defined conventions from web standards.
    • This means that Web Components created with WebC are compatible with server-side rendering (without duplicating author-written markup).
  • Compilation tools to aggregate component-level assets (CSS or JS) for critical CSS or client JavaScript.
  • Opt-in to scope your component CSS using WebC’s built-in CSS prefixer.
    • Or, use browser-native Shadow DOM style scoping (for future-compatibility when Declarative Shadow DOM browser support is ubiquitous)
  • Progressive-enhancement friendly.
  • Streaming friendly.
  • Shadow DOM friendly.
  • Async friendly.

Integrations/Plugins

Testimonials

“javascript frameworks are dead to me”—Andy Bell

“The DX and authoring model you landed on here looks fantastic”—Addy Osmani

“Really like the programmatic API approach over using a bundler to pre-compile and then serve.”—Harminder Virk

Similar Works

Folks doing similar things with Web Components: check them out!

Installation

Note: if you’re not building a plugin or integration for WebC, you can probably skip this section!

It’s available on npm as @11ty/webc:

npm install @11ty/webc

This is an ESM project and as such requires a "type": "module" in your package.json (or use the .mjs file extension).

import { WebC } from "@11ty/webc";

You can use this in a CommonJS file via dynamic import:

(async function() {
	const { WebC } = await import("@11ty/webc");
})();

Examples

JavaScript API

import { WebC } from "@11ty/webc";

let page = new WebC();

// This enables aggregation of CSS and JS
// As of 0.4.0+ this is disabled by default
page.setBundlerMode(true);

// File
page.setInputPath("page.webc");

// Or, a String
// page.setContent(`<p>Hello!</p>`);

let { html, css, js, components } = await page.compile();

// Or, Readable Streams for each
let { html, css, js } = await page.stream();

It’s HTML

If WebC looks familiar, that’s because WebC is HTML. These are single file HTML components but don’t require any special element conventions (for example Vue’s single file component uses a top-level <template> for markup). Using <template> in a WebC file will output 👀 a <template> element.

<!doctype html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		<title>WebC Example</title>
	</head>
	<body>
		WebC *is* HTML.
	</body>
</html>
  • Uses parse5 to parse WebC HTML as modern browsers do (credit to @DasSurma’s work with Vite here)
  • <!doctype html> is optional (will be added automatically if the content starts with <html).
  • Throws a helpful error if it encounters quirks mode markup.

HTML Imports (kidding… kinda)

To use components, we provide a few options: registering them globally via JavaScript or dynamically declaratively importing directly in your WebC file via webc:import.

Register global components

import { WebC } from "@11ty/webc";

let page = new WebC();

// Pass in a glob, using the file name as component name
page.defineComponents("components/**.webc");

// Array of file names, using file name as component name
page.defineComponents(["components/my-component.webc"]);

// Object maps component name to file name
page.defineComponents({
	"my-component": "components/my-component.webc"
});

And now you can use them in your WebC files without importing!

Consider this page.webc file:

<!doctype html>
<title>WebC Example</title>
<my-component></my-component>

When compiled, this will expand <my-component> to include the contents inside of components/my-component.webc.

If the components/my-component.webc file contains:

Components don’t need a root element, y’all.

Compiling page.webc will return the following HTML:

<!doctype html>
<html>
	<head>
		<title>WebC Example</title>
	</head>
<body>
	Components don’t need a root element, y’all.
</body>
</html>

Tricky trick: you aren’t limited to custom element names (e.g. my-component) here. You can use p, blockquote, h1, or any tag name to remap any HTML element globally. A more useful example might be an img component that uses the Eleventy Image utility to optimize all images in your project.

Dynamic import

See webc:import on the WebC Reference

Remapping components

See webc:is on the WebC Reference

Component Markup

Keep that host component HTML

See webc:keep on the WebC Reference

Slots

See Slots on the WebC Reference

Aggregating CSS and JS

Enabling Bundler Mode (page.setBundlerMode(true)) aggregates CSS and JS found in WebC components. Bundler mode is disabled by default (but enabled by default in the Eleventy WebC plugin).

As noted in the JavaScript API section above, the compile method returns four different properties:

page.setBundlerMode(true);

let { html, css, js, components } = await page.compile();

By default, <style> and <script> elements in component files are removed from individual component markup and aggregated together for re-use elsewhere (you could write this to a file, or use as Critical CSS in another layout template—the Eleventy plugin will smooth this over for you). This includes <link rel="stylesheet"> and <script src> when the URLs point to files on the file system (remote URL sources are not yet supported).

Note that if a <style> is nested inside of declarative shadow root template (e.g. <template shadowrootmode> or the deprecated <template shadowroot>), it is also left as is and not aggregated.

You can also opt out of aggregation on a per-element basis using <style webc:keep> or <script webc:keep>.

page.webc:

<my-component>Default slot</my-component>

components/my-component.webc:

<style>
my-component {
	color: rebeccapurple;
}
</style>

Compilation results:

page.setBundlerMode(true);

let results = await page.compile();

// `results`:
{
	html: "<my-component>Default slot</my-component>",
	css: ["my-component { color: rebeccapurple; }"],
	js: [],
	components: ["page.webc", "components/my-component.webc"]
}

The order of aggregated styles and scripts is based on the dependency graph of the components in play (the order is noted in the components array, a list of component file names).

Scoped CSS

See webc:scoped on the WebC Reference

Custom Transforms

You can also transform individual element content using the setTransform method.

let component = new WebC();
let md = new MarkdownIt({ html: true });

component.setTransform("md", async (content) => {
	// async-friendly
	return md.render(content);
});

Now you can automatically transform markdown in your WebC templates via the webc:type attribute.

<template webc:type="md">
# Header
</template>

Compiles to:

<h1>Header</h1>
  • Bonus feature: webc:type supports a comma separated list of transforms.

Note that the <template webc:type> node is compiled away. If you’d like to keep it around, use webc:keep (e.g. <template webc:type webc:keep>).

We do provide two built-in transforms in WebC: JavaScript Render Functions (webc:type="render") and CSS scoping (webc:scoped). Those are covered in separate sections. You can override these with the setTransform API but it is generally recommended to add your own named transform!

Conditionals

See webc:if on the WebC Reference

Loops

See webc:for on the WebC Reference

Attributes

See Attributes and webc:root on the WebC Reference

Properties (or Props)

See Props (properties) on the WebC Reference

Dynamic attributes and properties

See Dynamic Attributes and Properties on the WebC Reference

Setting multiple attributes

See @attributes on the WebC Reference

JavaScript Render Functions

See webc:type (JavaScript Render Functions) on the WebC Reference

Setting HTML

See @html on the WebC Reference

Setting Text

See @text on the WebC Reference

Helper Functions

If you want to add custom JavaScript functions for use in render functions, @html, or dynamic attributes you can use the setHelper method.

import { WebC } from "@11ty/webc";

let page = new WebC();

page.setHelper("alwaysBlue", () => {
	return "Blue"
});

And alwaysBlue() is now available:

<script webc:type="js">
alwaysBlue()
</script>

Raw Content (no WebC processing)

See webc:raw on the WebC Reference

Subtleties and Limitations

See Subtleties and Limitations on the WebC Reference