├── .gitignore
├── .npmignore
├── test
├── render-plugin
│ ├── webc
│ │ └── my-component.webc
│ ├── page.md
│ └── eleventy.config.mjs
├── sample-2
│ ├── _includes
│ │ └── component.webc
│ ├── page.webc
│ ├── eleventy.config.js
│ └── _layouts
│ │ └── layout.webc
├── default-components
│ ├── _includes
│ │ └── say-hello.webc
│ ├── _components
│ │ └── say-hello.webc
│ ├── page.webc
│ └── eleventy.config.js
├── nested-layouts
│ ├── _components
│ │ ├── reprocess-me.webc
│ │ └── say-hello.webc
│ ├── page.webc
│ ├── _includes
│ │ ├── layout.webc
│ │ └── base.webc
│ └── eleventy.config.js
├── raw-layout-html
│ ├── _includes
│ │ ├── reprocess-me.webc
│ │ └── say-hello.webc
│ ├── page.webc
│ ├── eleventy.config.js
│ └── _layouts
│ │ └── layout.webc
├── shortcodes-issue-16
│ ├── _components
│ │ └── say-hello.webc
│ ├── page.webc
│ └── eleventy.config.js
├── components-in-layouts
│ ├── page1.webc
│ ├── _components
│ │ ├── inner.webc
│ │ └── outer.webc
│ ├── page2.webc
│ ├── page3.webc
│ ├── _includes
│ │ ├── layout.webc
│ │ └── base.webc
│ └── eleventy.config.js
├── permalink-string
│ ├── page.webc
│ ├── page2.webc
│ └── eleventy.config.js
├── sample-page-global-components
│ ├── _includes
│ │ └── page1-components
│ │ │ └── say-hello.webc
│ ├── eleventy.config.js
│ ├── page.webc
│ └── _layouts
│ │ └── layout.webc
├── webc-component-in-layout
│ ├── page.liquid
│ ├── _components
│ │ └── twitter-share.webc
│ ├── _includes
│ │ └── layout.liquid
│ └── eleventy.config.mjs
├── sample-html-preprocess
│ ├── _includes
│ │ └── say-hello.webc
│ ├── page.html
│ └── eleventy.config.js
├── sample-non-webc-layout
│ ├── _includes
│ │ └── say-hello.webc
│ ├── page.webc
│ ├── eleventy.config.js
│ └── _layouts
│ │ └── layout.liquid
├── custom-permalink-issue-32
│ ├── page.webc
│ └── eleventy.config.js
├── sample-page-global-components-relative-to-inputpath
│ ├── _includes
│ │ └── page1-components
│ │ │ └── say-hello.webc
│ ├── page.webc
│ ├── eleventy.config.js
│ └── _layouts
│ │ └── layout.webc
├── uid-leftovers
│ ├── page.webc
│ ├── _layouts
│ │ └── layout.webc
│ └── eleventy.config.js
├── custom-permalink-not-dynamic-issue-32
│ ├── page.webc
│ └── eleventy.config.js
├── sample-transform
│ ├── _includes
│ │ └── say-hello.webc
│ ├── page.liquid
│ └── eleventy.config.js
├── bundler-to-file
│ └── index.webc
├── custom-js-front-matter
│ ├── page.liquid
│ └── eleventy.config.js
├── generic.eleventy.config.js
├── bundler-helpers
│ ├── eleventy.config.js
│ └── index.webc
├── custom-permalink
│ ├── eleventy.config.js
│ └── page.webc
├── sample-1
│ ├── page.webc
│ ├── eleventy.config.js
│ └── _layouts
│ │ └── layout.webc
├── sample-universal-helpers
│ ├── page.webc
│ └── eleventy.config.js
├── script-and-style-buckets
│ ├── page.webc
│ ├── _components
│ │ └── my-button.webc
│ ├── eleventy.config.mjs
│ └── _layouts
│ │ └── layout.webc
├── sample-permalink-false-webc
│ ├── page.webc
│ └── eleventy.config.js
├── sample-permalink-false
│ ├── page.liquid
│ └── eleventy.config.js
├── test-chdir.mjs
└── test.mjs
├── .vscode
└── settings.json
├── .editorconfig
├── .github
└── workflows
│ ├── ci.yml
│ └── release.yml
├── package.json
├── src
├── eleventyWebcTransform.js
├── dynamicScript.js
└── eleventyWebcTemplate.js
├── README.md
└── eleventyWebcPlugin.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | test
2 | .*
--------------------------------------------------------------------------------
/test/render-plugin/webc/my-component.webc:
--------------------------------------------------------------------------------
1 | My component
--------------------------------------------------------------------------------
/test/sample-2/_includes/component.webc:
--------------------------------------------------------------------------------
1 | This is a component.
--------------------------------------------------------------------------------
/test/default-components/_includes/say-hello.webc:
--------------------------------------------------------------------------------
1 | INCLUDES DIR
--------------------------------------------------------------------------------
/test/nested-layouts/_components/reprocess-me.webc:
--------------------------------------------------------------------------------
1 | REPROCESSED
--------------------------------------------------------------------------------
/test/raw-layout-html/_includes/reprocess-me.webc:
--------------------------------------------------------------------------------
1 | REPROCESSED
--------------------------------------------------------------------------------
/test/default-components/_components/say-hello.webc:
--------------------------------------------------------------------------------
1 | COMPONENTS DIR
--------------------------------------------------------------------------------
/test/shortcodes-issue-16/_components/say-hello.webc:
--------------------------------------------------------------------------------
1 | COMPONENTS DIR
--------------------------------------------------------------------------------
/test/components-in-layouts/page1.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.webc
3 | ---
4 | Page
--------------------------------------------------------------------------------
/test/permalink-string/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: "index.html"
3 | ---
4 | Hello
--------------------------------------------------------------------------------
/test/sample-page-global-components/_includes/page1-components/say-hello.webc:
--------------------------------------------------------------------------------
1 | HELLO
--------------------------------------------------------------------------------
/test/components-in-layouts/_components/inner.webc:
--------------------------------------------------------------------------------
1 | Test
2 |
--------------------------------------------------------------------------------
/test/components-in-layouts/_components/outer.webc:
--------------------------------------------------------------------------------
1 | Test
2 |
--------------------------------------------------------------------------------
/test/components-in-layouts/page2.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.webc
3 | ---
4 | Other page
--------------------------------------------------------------------------------
/test/permalink-string/page2.webc:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: "`index2.html`"
3 | ---
4 | Hello
--------------------------------------------------------------------------------
/test/webc-component-in-layout/page.liquid:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.liquid
3 | ---
4 | Hello
--------------------------------------------------------------------------------
/test/sample-html-preprocess/_includes/say-hello.webc:
--------------------------------------------------------------------------------
1 | HELLO
--------------------------------------------------------------------------------
/test/sample-non-webc-layout/_includes/say-hello.webc:
--------------------------------------------------------------------------------
1 | HELLO
2 |
--------------------------------------------------------------------------------
/test/custom-permalink-issue-32/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | ---
4 |
--------------------------------------------------------------------------------
/test/sample-page-global-components-relative-to-inputpath/_includes/page1-components/say-hello.webc:
--------------------------------------------------------------------------------
1 | HELLO
--------------------------------------------------------------------------------
/test/uid-leftovers/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.webc
3 | ---
4 |
--------------------------------------------------------------------------------
/test/sample-html-preprocess/page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | WHO IS THIS
4 | hi
--------------------------------------------------------------------------------
/test/custom-permalink-not-dynamic-issue-32/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | ---
4 |
--------------------------------------------------------------------------------
/test/sample-transform/_includes/say-hello.webc:
--------------------------------------------------------------------------------
1 | HELLO
--------------------------------------------------------------------------------
/test/components-in-layouts/page3.webc:
--------------------------------------------------------------------------------
1 | No layouts here
2 |
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "editor.trimAutoWhitespace": false,
3 | "files.trimTrailingWhitespaceInRegexAndStrings": false
4 | }
--------------------------------------------------------------------------------
/test/render-plugin/page.md:
--------------------------------------------------------------------------------
1 | # Hello
2 |
3 | {% renderTemplate "webc" %}
4 |
5 | {% endrenderTemplate %}
--------------------------------------------------------------------------------
/test/nested-layouts/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.webc
3 | ---
4 | Testing
5 |
--------------------------------------------------------------------------------
/test/bundler-to-file/index.webc:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/test/custom-js-front-matter/page.liquid:
--------------------------------------------------------------------------------
1 | ---js
2 | const frontmatterdata = "HELLO FROM FRONT MATTER";
3 | ---
4 | {{ frontmatterdata }}
--------------------------------------------------------------------------------
/test/components-in-layouts/_includes/layout.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base.webc
3 | ---
4 |
5 |
--------------------------------------------------------------------------------
/test/nested-layouts/_components/say-hello.webc:
--------------------------------------------------------------------------------
1 | Using raw here to test reprocessing in the layout
2 |
--------------------------------------------------------------------------------
/test/nested-layouts/_includes/layout.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: base.webc
3 | ---
4 | Base
5 |
6 |
--------------------------------------------------------------------------------
/test/raw-layout-html/_includes/say-hello.webc:
--------------------------------------------------------------------------------
1 | Using raw here to test reprocessing in the layout
2 |
--------------------------------------------------------------------------------
/test/uid-leftovers/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/test/generic.eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | }
6 |
--------------------------------------------------------------------------------
/test/sample-transform/page.liquid:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | ---
4 |
5 |
6 | WHO IS THIS
7 | hi
8 | {{ frontmatterdata }}
--------------------------------------------------------------------------------
/test/default-components/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | ---
4 |
5 |
6 | WHO IS THIS
7 | hi
8 |
--------------------------------------------------------------------------------
/test/bundler-helpers/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | }
6 |
--------------------------------------------------------------------------------
/test/custom-permalink/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | }
6 |
--------------------------------------------------------------------------------
/test/permalink-string/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | }
6 |
--------------------------------------------------------------------------------
/test/default-components/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | }
6 |
--------------------------------------------------------------------------------
/test/sample-1/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.webc
4 | ---
5 |
6 |
7 | WHO IS THIS
8 | hi
9 |
--------------------------------------------------------------------------------
/test/sample-2/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.webc
4 | ---
5 |
6 |
7 | WHO IS THIS
8 | hi
9 |
--------------------------------------------------------------------------------
/test/sample-universal-helpers/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | globalData: hello
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/test/raw-layout-html/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.webc
4 | ---
5 |
6 |
7 | WHO IS THIS
8 | hi
9 |
--------------------------------------------------------------------------------
/test/shortcodes-issue-16/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | ---
4 |
5 | {{frontmatterdata}}
6 | {% testing %}
7 | {{ "lowercase" | uppercase }}
8 |
--------------------------------------------------------------------------------
/test/sample-non-webc-layout/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.liquid
4 | ---
5 |
6 |
7 | WHO IS THIS
8 | hi
9 |
--------------------------------------------------------------------------------
/test/custom-js-front-matter/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: false,
6 | });
7 | }
8 |
--------------------------------------------------------------------------------
/test/script-and-style-buckets/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | layout: layout.webc
3 | ---
4 |
5 | Hello everyone!
6 | Buttons are purple
7 |
8 |
--------------------------------------------------------------------------------
/test/webc-component-in-layout/_components/twitter-share.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/test/custom-permalink/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | permalink: "slugify(frontmatterdata) + '.html'"
4 | ---
5 |
6 |
7 | WHO IS THIS
8 | hi
9 |
--------------------------------------------------------------------------------
/test/bundler-helpers/index.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 | {% css %}/* Bundle 2 */{% endcss %}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/test/script-and-style-buckets/_components/my-button.webc:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/test/webc-component-in-layout/_includes/layout.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {% renderTemplate "webc" %}{% endrenderTemplate %}
7 | {{ content }}
8 |
9 |
--------------------------------------------------------------------------------
/test/sample-1/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 |
6 | return {
7 | dir: {
8 | includes: "_includes",
9 | layouts: "_layouts",
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/test/custom-permalink-issue-32/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addGlobalData("permalink", () => ((data) => `${data.page.filePathStem}.html`));
5 |
6 | eleventyConfig.addPlugin(EleventyWebcPlugin);
7 | }
8 |
--------------------------------------------------------------------------------
/test/sample-page-global-components/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 |
6 | return {
7 | dir: {
8 | includes: "_includes",
9 | layouts: "_layouts",
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/test/sample-page-global-components-relative-to-inputpath/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.webc
4 | webc:
5 | components: "./_includes/page1-components/*.webc"
6 | ---
7 |
8 |
9 | WHO IS THIS
10 | hi
11 |
--------------------------------------------------------------------------------
/test/sample-permalink-false-webc/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: false
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/sample-page-global-components/page.webc:
--------------------------------------------------------------------------------
1 | ---
2 | frontmatterdata: "HELLO FROM FRONT MATTER"
3 | layout: layout.webc
4 | webc:
5 | components: "~/test/sample-page-global-components/_includes/page1-components/*.webc"
6 | ---
7 |
8 |
9 | WHO IS THIS
10 | hi
11 |
--------------------------------------------------------------------------------
/test/sample-permalink-false/page.liquid:
--------------------------------------------------------------------------------
1 | ---
2 | permalink: false
3 | ---
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/test/custom-permalink-not-dynamic-issue-32/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addGlobalData("dynamicPermalink", false);
5 | eleventyConfig.addGlobalData("permalink", "page.html");
6 |
7 | eleventyConfig.addPlugin(EleventyWebcPlugin);
8 | }
9 |
--------------------------------------------------------------------------------
/test/render-plugin/eleventy.config.mjs:
--------------------------------------------------------------------------------
1 | import WebcPlugin from "../../eleventyWebcPlugin.js";
2 | import { RenderPlugin } from "@11ty/eleventy";
3 |
4 | export default function (eleventyConfig) {
5 | eleventyConfig.addPlugin(WebcPlugin, {
6 | components: "./test/render-plugin/webc/*.webc"
7 | });
8 |
9 | eleventyConfig.addPlugin(RenderPlugin);
10 | }
11 |
--------------------------------------------------------------------------------
/test/sample-page-global-components-relative-to-inputpath/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 |
6 | return {
7 | dir: {
8 | includes: "_includes",
9 | layouts: "_layouts",
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | indent_size = 2
6 | end_of_line = lf
7 | insert_final_newline = false
8 | trim_trailing_whitespace = true
9 | charset = utf-8
10 |
11 | [*.js]
12 | insert_final_newline = true
13 |
14 | [test/*.js]
15 | trim_trailing_whitespace = false
16 |
17 | [test/*.mjs]
18 | trim_trailing_whitespace = false
19 |
--------------------------------------------------------------------------------
/test/nested-layouts/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "test/nested-layouts/_components/**/*.webc"
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/sample-permalink-false/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | useTransform: true
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | layouts: "_layouts",
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/sample-permalink-false-webc/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | useTransform: true
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | layouts: "_layouts",
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/components-in-layouts/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "test/components-in-layouts/_components/**/*.webc"
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/test/raw-layout-html/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "test/raw-layout-html/_includes/*.webc"
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | layouts: "_layouts",
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/sample-non-webc-layout/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "./test/sample-non-webc-layout/_includes/*.webc"
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | layouts: "_layouts",
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/nested-layouts/_includes/base.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/sample-html-preprocess/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "./test/sample-html-preprocess/_includes/*.webc",
6 | });
7 |
8 | return {
9 | dir: {
10 | includes: "_includes",
11 | },
12 | htmlTemplateEngine: "webc"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/test/sample-2/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "test/sample-2/_includes/**/*.webc"
6 | });
7 | // eleventyConfig.addPlugin(EleventyWebcPlugin);
8 |
9 | return {
10 | dir: {
11 | includes: "_includes",
12 | layouts: "_layouts",
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/test/components-in-layouts/_includes/base.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/sample-transform/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
5 | components: "./test/sample-transform/_includes/*.webc",
6 | useTransform: true,
7 | transformData: { pkg: require("../../package.json") }
8 | });
9 |
10 | return {
11 | dir: {
12 | includes: "_includes",
13 | }
14 | }
15 | }
--------------------------------------------------------------------------------
/test/sample-universal-helpers/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addPlugin(EleventyWebcPlugin);
5 | eleventyConfig.addFilter("testing", function(arg) {
6 | return arg + "Always return this" + this.page.url
7 | });
8 |
9 | return {
10 | dir: {
11 | includes: "_includes",
12 | layouts: "_layouts",
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/test/raw-layout-html/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/webc-component-in-layout/eleventy.config.mjs:
--------------------------------------------------------------------------------
1 | import { RenderPlugin } from "@11ty/eleventy";
2 | import WebcPlugin from "../../eleventyWebcPlugin.js";
3 |
4 | export default function(eleventyConfig) {
5 | eleventyConfig.addPlugin(RenderPlugin);
6 |
7 | eleventyConfig.addPlugin(WebcPlugin, {
8 | components: "./test/webc-component-in-layout/_components/*.webc"
9 | });
10 |
11 | return {
12 | dir: {
13 | includes: "_includes",
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/test/uid-leftovers/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | let i = 0;
4 |
5 | module.exports = function (eleventyConfig) {
6 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
7 | before: (component) => {
8 | component.setUidFunction(function() {
9 | return `webc-${i++}`;
10 | });
11 | }
12 | });
13 |
14 | return {
15 | dir: {
16 | includes: "_includes",
17 | layouts: "_layouts",
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/test/sample-non-webc-layout/_layouts/layout.liquid:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | {{ content }}
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/shortcodes-issue-16/eleventy.config.js:
--------------------------------------------------------------------------------
1 | const EleventyWebcPlugin = require("../../eleventyWebcPlugin.js");
2 |
3 | module.exports = function (eleventyConfig) {
4 | eleventyConfig.addShortcode("testing", () => {
5 | // WebC in a shortcode!
6 | return "";
7 | });
8 |
9 | eleventyConfig.addFilter("uppercase", (str) => {
10 | return str.toUpperCase();
11 | });
12 |
13 |
14 | eleventyConfig.addPlugin(EleventyWebcPlugin, {
15 | components: "./test/shortcodes-issue-16/_components/*.webc"
16 | });
17 | };
18 |
--------------------------------------------------------------------------------
/test/sample-1/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/script-and-style-buckets/eleventy.config.mjs:
--------------------------------------------------------------------------------
1 | import { RenderPlugin } from "@11ty/eleventy";
2 | import WebcPlugin from "../../eleventyWebcPlugin.js";
3 |
4 | export default function (eleventyConfig) {
5 | eleventyConfig.addPlugin(RenderPlugin);
6 | eleventyConfig.addPlugin(WebcPlugin, {
7 | components: "test/script-and-style-buckets/_components/**/*.webc"
8 | });
9 | // eleventyConfig.addPlugin(eleventyConfig => {
10 | // console.log( eleventyConfig.javascriptFunctions );
11 | // })
12 |
13 | return {
14 | dir: {
15 | includes: "_includes",
16 | layouts: "_layouts",
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/script-and-style-buckets/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/sample-2/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/sample-page-global-components/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/test/sample-page-global-components-relative-to-inputpath/_layouts/layout.webc:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Node Unit Tests
2 | on: push
3 | permissions: read-all
4 | jobs:
5 | build:
6 | runs-on: ${{ matrix.os }}
7 | strategy:
8 | matrix:
9 | os: ["ubuntu-latest", "macos-latest", "windows-latest"]
10 | node: ["18", "20", "22", "24"]
11 | name: Node.js ${{ matrix.node }} on ${{ matrix.os }}
12 | steps:
13 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # 4.1.7
14 | - name: Setup node
15 | uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # 4.0.3
16 | with:
17 | node-version: ${{ matrix.node }}
18 | # cache: npm
19 | - run: npm install
20 | - run: npm test
21 | env:
22 | YARN_GPG: no
23 |
--------------------------------------------------------------------------------
/test/test-chdir.mjs:
--------------------------------------------------------------------------------
1 | import test from "ava";
2 | import Eleventy from "@11ty/eleventy";
3 |
4 | function normalize(str) {
5 | return str.trim().replace(/\r\n/g, "\n");
6 | }
7 |
8 | // This needs a CHDIR because the default `components` glob is relative to the root directory (not the input directory)
9 | console.log("Make sure you are running `npm run test` and not `npx ava`");
10 | process.chdir("./test/default-components/");
11 |
12 | test("New default components directory, issue #14", async t => {
13 | let elev = new Eleventy("page.webc", "_site", {
14 | configPath: "eleventy.config.js"
15 | });
16 |
17 | let results = await elev.toJSON();
18 | let [result] = results;
19 | t.is(normalize(result.content), `COMPONENTS DIR
20 | COMPONENTS DIR
21 | WHO IS THIS
22 | hi
23 | HELLO FROM FRONT MATTER`);
24 | });
25 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Publish Release to npm
2 | on:
3 | release:
4 | types: [published]
5 | permissions: read-all
6 | jobs:
7 | build:
8 | runs-on: ubuntu-latest
9 | environment: GitHub Publish
10 | permissions:
11 | contents: read
12 | id-token: write
13 | steps:
14 | - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # 4.1.7
15 | - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # 4.0.3
16 | with:
17 | node-version: "22"
18 | registry-url: 'https://registry.npmjs.org'
19 | - run: npm install -g npm@latest
20 | - run: npm ci
21 | - run: npm test
22 | - if: ${{ github.event.release.tag_name != '' && env.NPM_PUBLISH_TAG != '' }}
23 | run: npm publish --provenance --access=public --tag=${{ env.NPM_PUBLISH_TAG }}
24 | env:
25 | NPM_PUBLISH_TAG: ${{ contains(github.event.release.tag_name, '-beta.') && 'beta' || 'latest' }}
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@11ty/eleventy-plugin-webc",
3 | "version": "0.12.0-beta.7",
4 | "description": "WebC support for Eleventy adds for Single File Web Components",
5 | "main": "eleventyWebcPlugin.js",
6 | "scripts": {
7 | "test": "npx ava --no-worker-threads"
8 | },
9 | "publishConfig": {
10 | "access": "public"
11 | },
12 | "license": "MIT",
13 | "engines": {
14 | "node": ">= 18"
15 | },
16 | "11ty": {
17 | "compatibility": ">=3.0.0"
18 | },
19 | "funding": {
20 | "type": "opencollective",
21 | "url": "https://opencollective.com/11ty"
22 | },
23 | "keywords": [
24 | "eleventy",
25 | "eleventy-plugin",
26 | "web-components",
27 | "custom-elements"
28 | ],
29 | "author": "Zach Leatherman (https://zachleat.com/)",
30 | "repository": {
31 | "type": "git",
32 | "url": "git://github.com/11ty/eleventy-plugin-webc.git"
33 | },
34 | "bugs": "https://github.com/11ty/eleventy-plugin-webc/issues",
35 | "homepage": "https://github.com/11ty/eleventy-plugin-webc",
36 | "ava": {
37 | "failFast": true,
38 | "files": [
39 | "./test/test*.js",
40 | "./test/test*.mjs"
41 | ],
42 | "watchMode": {
43 | "ignoreChanges": [
44 | "**/_site/**",
45 | ".cache"
46 | ]
47 | }
48 | },
49 | "dependencies": {
50 | "@11ty/eleventy-plugin-bundle": "^3.0.7",
51 | "@11ty/webc": "^0.12.0-beta.2",
52 | "import-module-string": "^2.0.3"
53 | },
54 | "devDependencies": {
55 | "@11ty/eleventy": "^3.1.2",
56 | "ava": "^6.4.1"
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/eleventyWebcTransform.js:
--------------------------------------------------------------------------------
1 | module.exports = function(eleventyConfig, options = {}) {
2 | let componentsMap = false; // cache the glob search
3 |
4 | eleventyConfig.on("eleventy.before", () => {
5 | componentsMap = false;
6 | });
7 |
8 | let scopedHelpers = new Set(options.scopedHelpers);
9 |
10 | eleventyConfig.addTransform("@11ty/eleventy-plugin-webc", async function(content) {
11 | // Skip non-.html output
12 | // Skip .webc input
13 | if(this.inputPath.endsWith(".webc") || !(this.outputPath || "").endsWith(".html")) {
14 | return content;
15 | }
16 |
17 | // TODO prevent double processing with the Render plugin with WebC
18 | // https://www.11ty.dev/docs/plugins/render/
19 | try {
20 | const { WebC } = await import("@11ty/webc");
21 | let page = new WebC();
22 |
23 | if(componentsMap === false && options.components) {
24 | componentsMap = WebC.getComponentsMap(options.components); // "./_components/**/*.webc"
25 | }
26 |
27 | for(let helperName in eleventyConfig.javascriptFunctions) {
28 | page.setHelper(helperName, eleventyConfig.javascriptFunctions[helperName], scopedHelpers.has(helperName));
29 | }
30 |
31 | page.setBundlerMode(false);
32 | page.defineComponents(componentsMap);
33 | page.setContent(content, this.outputPath);
34 |
35 | let { html } = await page.compile({
36 | // global data
37 | data: options.transformData
38 | });
39 | return html;
40 | } catch(e) {
41 | console.error( `[11ty/eleventy-plugin-webc] Error transforming ${this.inputPath}`, e );
42 | throw e;
43 | }
44 |
45 | return content;
46 | });
47 | }
48 |
--------------------------------------------------------------------------------
/src/dynamicScript.js:
--------------------------------------------------------------------------------
1 | // TODO move this upstream into import-module-string
2 | // Code cribbed from WebC’s attributeSerializer.js
3 | async function evaluateInlineCode(codeString, options = {}) {
4 | let { filePath, context, data } = Object.assign({ data: {} }, options);
5 |
6 | let { parseCode, walkCode, importFromString } = await import("import-module-string");
7 | let varsInUse = [];
8 | try {
9 | let {used} = walkCode(parseCode(codeString));
10 | varsInUse = used;
11 | } catch(e) {
12 | let errorString = `Error parsing inline code: \`${codeString}\``;
13 |
14 | // Issue #45: very defensive error message here. We only throw this error when an error is thrown during compilation.
15 | if(e.message.startsWith("Unexpected token ") && codeString.match(/\bclass\b/) && !codeString.match(/\bclass\b\s*\{/)) {
16 | throw new Error(`${errorString ? `${errorString} ` : ""}\`class\` is a reserved word in JavaScript. Change \`class\` to \`this.class\` instead!`);
17 | }
18 |
19 | throw new Error(`${errorString}\nOriginal error message: ${e.message}`);
20 | }
21 |
22 | let argString = "";
23 | if(!Array.isArray(varsInUse)) {
24 | varsInUse = Array.from(varsInUse)
25 | }
26 | if(varsInUse.length > 0) {
27 | argString = `{ ${varsInUse.join(", ")} }`;
28 | }
29 |
30 | let code = `export default function(${argString}) { return ${codeString} };`;
31 |
32 | let evaluated = await importFromString(code, {
33 | filePath,
34 | implicitExports: false,
35 | }).then(mod => {
36 | let fn = mod.default;
37 | if(context) {
38 | return fn.call(context, data);
39 | }
40 | return fn(data);
41 | }).catch(e => {
42 | throw new Error(`Error evaluating inline code: \`${codeString}\``, { cause: e });
43 | });
44 |
45 | return evaluated;
46 | }
47 |
48 | module.exports = {
49 | evaluateInlineCode
50 | };
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | # eleventy-plugin-webc 🕚⚡️🎈🐀
4 |
5 | Adds support for [WebC, the single file web component format](https://github.com/11ty/webc), to Eleventy.
6 |
7 | * [This documentation has moved to 11ty.dev](https://www.11ty.dev/docs/languages/webc/).
8 | * Watch the [crash course in Eleventy WebC on YouTube](https://www.youtube.com/watch?v=X-Bpjrkz-V8).
9 | * Watch the [Interactive Components tutorial on YouTube](https://www.youtube.com/watch?v=p0wDUK0Z5Nw)
10 |
11 | [](https://www.npmjs.com/package/@11ty/eleventy-plugin-webc)
12 |
13 | - Star [Eleventy on GitHub](https://github.com/11ty/eleventy/)!
14 | - Follow us on Twitter [@eleven_ty](https://twitter.com/eleven_ty)
15 | - Support [11ty on Open Collective](https://opencollective.com/11ty)
16 | - Subscribe to our [YouTube channel](https://11ty.dev/youtube)
17 |
18 | ## [Documentation](https://www.11ty.dev/docs/languages/webc/)
19 |
20 | This documentation has [moved to 11ty.dev](https://www.11ty.dev/docs/languages/webc/).
21 |
22 | ## Features
23 |
24 | * Brings first-class **components** to Eleventy.
25 | * Expand any HTML element (including custom elements) to HTML with defined conventions from web standards.
26 | * This means that Web Components created with WebC are compatible with server-side rendering (without duplicating author-written markup)
27 | * WebC components are [Progressive Enhancement friendly](https://www.youtube.com/watch?v=p0wDUK0Z5Nw).
28 | * Get first-class **incremental builds** (for page templates, components, and Eleventy layouts) when [used with `--incremental`](https://www.11ty.dev/docs/usage/#incremental-for-partial-incremental-builds)
29 | * Streaming friendly (stream on the Edge 👀)
30 | * Easily scope component CSS (or use your own scoping utility).
31 | * Tired of importing components? Use global or per-page no-import components.
32 | * Shadow DOM friendly (works with or without Shadow DOM)
33 | * All configuration extensions/hooks into WebC are async-friendly out of the box.
34 | * Bundler mode: Easily roll up the CSS and JS in-use by WebC components on a page for page-specific bundles. Dirt-simple critical CSS/JS to only load the code you need.
35 | * For more complex templating needs, render any existing Eleventy template syntax (Liquid, markdown, Nunjucks, etc.) inside of WebC.
36 | * Works great with [is-land](https://www.11ty.dev/docs/plugins/partial-hydration/) for web component hydration.
37 |
--------------------------------------------------------------------------------
/eleventyWebcPlugin.js:
--------------------------------------------------------------------------------
1 | const pkg = require("./package.json");
2 | const templatePlugin = require("./src/eleventyWebcTemplate.js");
3 | const transformPlugin = require("./src/eleventyWebcTransform.js");
4 |
5 | module.exports = function(eleventyConfig, options = {}) {
6 | eleventyConfig.versionCheck(pkg["11ty"].compatibility);
7 |
8 | // Error for removed filters.
9 | eleventyConfig.addFilter("webcGetCss", () => {
10 | throw new Error("webcGetCss was removed from @11ty/eleventy-plugin-webc. Use the `getBundle('css')` shortcode instead.")
11 | });
12 |
13 | // Error for removed filters.
14 | eleventyConfig.addFilter("webcGetJs", () => {
15 | throw new Error("webcGetJs was removed from @11ty/eleventy-plugin-webc. Use the `getBundle('js')` shortcode instead.")
16 | })
17 |
18 |
19 | options = Object.assign({
20 | components: "_components/**/*.webc", // glob for no-import global components
21 | scopedHelpers: ["css", "js", "html"],
22 | useTransform: false, // global transform
23 | transformData: {}, // extra global data for transforms specifically
24 | }, options);
25 |
26 | options.bundlePluginOptions = Object.assign({
27 | hoistDuplicateBundlesFor: ["css", "js"]
28 | }, options.bundlePluginOptions);
29 |
30 | if(options.components) {
31 | let components = options.components;
32 | if(!Array.isArray(components)) {
33 | components = [components];
34 | }
35 |
36 | for(let entry of components) {
37 | if(entry.startsWith("npm:")) {
38 | continue;
39 | }
40 |
41 | eleventyConfig.addWatchTarget(entry);
42 |
43 | // Opt-out of Eleventy to process components
44 | // Note that Eleventy’s default ignores already have _includes/**
45 |
46 | // This will cause component files outside of _includes to not be watched: https://github.com/11ty/eleventy-plugin-webc/issues/29
47 | // Fixed in @11ty/eleventy@2.0.0-canary.18: https://github.com/11ty/eleventy/issues/893
48 | eleventyConfig.ignores.add(entry);
49 | }
50 | }
51 |
52 | // v0.12.0 upstream
53 | // `bundlePluginOptions.toFileDirectory` (via Bundle Plugin changes) default changed from "bundle" to ""
54 | // https://github.com/11ty/eleventy-plugin-bundle/releases/tag/v2.0.0
55 |
56 | eleventyConfig.addBundle("html", Object.assign({}, options.bundlePluginOptions, {
57 | hoist: options.bundlePluginOptions.hoistDuplicateBundlesFor.includes("html"),
58 | }));
59 | eleventyConfig.addBundle("css", Object.assign({}, options.bundlePluginOptions, {
60 | hoist: options.bundlePluginOptions.hoistDuplicateBundlesFor.includes("css"),
61 | }));
62 | eleventyConfig.addBundle("js", Object.assign({}, options.bundlePluginOptions, {
63 | hoist: options.bundlePluginOptions.hoistDuplicateBundlesFor.includes("js")
64 | }));
65 |
66 | templatePlugin(eleventyConfig, options);
67 |
68 | if(options.useTransform) {
69 | transformPlugin(eleventyConfig, options);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/eleventyWebcTemplate.js:
--------------------------------------------------------------------------------
1 | const path = require("node:path");
2 | const debug = require("debug")("Eleventy:WebC");
3 |
4 | const { evaluateInlineCode } = require("./dynamicScript.js");
5 |
6 | function relativePath(inputPath, newGlob) {
7 | // project root
8 | if(newGlob.startsWith("~/")) {
9 | let rootRelativePath = "." + newGlob.slice(1);
10 | return rootRelativePath;
11 | }
12 |
13 | let { dir } = path.parse(inputPath);
14 | // globs must have forward slashes (even on Windows)
15 | let templateRelativePath = path.join(dir, newGlob).split(path.sep).join("/");
16 | return templateRelativePath;
17 | }
18 |
19 | function addContextToJavaScriptFunction(data, fn) {
20 | let CONTEXT_KEYS = ["eleventy", "page"];
21 | return function (...args) {
22 | for (let key of CONTEXT_KEYS) {
23 | if (data && data[key]) {
24 | this[key] = data[key];
25 | }
26 | }
27 |
28 | return fn.call(this, ...args);
29 | };
30 | }
31 |
32 | module.exports = function(eleventyConfig, options = {}) {
33 | // TODO remove this when WebC is moved out of plugin-land into core.
34 | eleventyConfig.addTemplateFormats("webc");
35 |
36 | let _WebC;
37 | let globalComponentManager;
38 | let componentsMap = false; // cache the glob search
39 | let scopedHelpers = new Set(options.scopedHelpers);
40 |
41 | eleventyConfig.on("eleventy.before", async () => {
42 | // Temporary workaround for ESM in CJS
43 | let { WebC, ComponentManager } = await import("@11ty/webc");
44 | _WebC = WebC;
45 | globalComponentManager = new ComponentManager();
46 |
47 | if(options.components) {
48 | componentsMap = WebC.getComponentsMap(options.components); // second argument is ignores here
49 | }
50 | });
51 |
52 | let templateConfig;
53 | eleventyConfig.on("eleventy.config", (cfg) => {
54 | templateConfig = cfg;
55 | });
56 |
57 | eleventyConfig.addExtension("webc", {
58 | outputFileExtension: "html",
59 |
60 | compileOptions: {
61 | permalink: function(contents, inputPath) {
62 | if(contents && typeof contents === "string") {
63 | return async (data) => {
64 | let combinedContextData = {
65 | ...this,
66 | ...data,
67 | };
68 |
69 | // Hard to know if this is JavaScript code or just a raw string value.
70 | return evaluateInlineCode(contents, {
71 | filePath: inputPath,
72 | context: combinedContextData,
73 | data: combinedContextData,
74 | }).catch(e => {
75 | debug("Error evaluating dynamic permalink, returning raw string contents instead: %o\n%O", contents, e);
76 | return contents;
77 | });
78 | }
79 | }
80 |
81 | return contents;
82 | }
83 | },
84 |
85 | compile: async function(inputContent, inputPath) {
86 | let page = new _WebC();
87 |
88 | page.setGlobalComponentManager(globalComponentManager);
89 | page.setBundlerMode(true);
90 | page.setContent(inputContent, inputPath);
91 |
92 | if(componentsMap) {
93 | page.defineComponents(componentsMap);
94 | }
95 |
96 | // Support both casings (I prefer getCss, but yeah)
97 | page.setHelper("getCss", (url, bucket) => this.config.javascriptFunctions.getBundle("css", bucket, url), scopedHelpers.has("getCss"));
98 | page.setHelper("getCSS", (url, bucket) => this.config.javascriptFunctions.getBundle("css", bucket, url), scopedHelpers.has("getCSS"));
99 |
100 | page.setHelper("getJs", (url, bucket) => this.config.javascriptFunctions.getBundle("js", bucket, url), scopedHelpers.has("getJs"));
101 | page.setHelper("getJS", (url, bucket) => this.config.javascriptFunctions.getBundle("js", bucket, url), scopedHelpers.has("getJS"));
102 |
103 | page.setTransform("11ty", async function(content) {
104 | let syntax = this["11ty:type"];
105 | if(syntax) {
106 | const { RenderPlugin } = await import("@11ty/eleventy");
107 | const CompileString = RenderPlugin.String;
108 |
109 | let fn = await CompileString(content, syntax, {
110 | templateConfig
111 | });
112 | return fn(this);
113 | }
114 | return content;
115 | });
116 |
117 | // Render function
118 | return async (data) => {
119 | // Add Eleventy JavaScript Functions as WebC helpers
120 | // Note that Universal Filters and Shortcodes populate into javascriptFunctions and will be present here
121 |
122 | for(let helperName in this.config.javascriptFunctions) {
123 | let helperFunction = addContextToJavaScriptFunction(data, this.config.javascriptFunctions[helperName]);
124 | page.setHelper(helperName, helperFunction, scopedHelpers.has(helperName));
125 | }
126 |
127 | let setupObject = {
128 | data,
129 | };
130 |
131 | if(data.webc?.components) {
132 | setupObject.components = _WebC.getComponentsMap(relativePath(data.page.inputPath, data.webc.components));
133 | }
134 |
135 | if(options.before && typeof options.before === "function") {
136 | await options.before(page);
137 | }
138 |
139 | let { html, css, js, buckets, components } = await page.compile(setupObject);
140 |
141 | // 2.0.0-canary.19+
142 | this.addDependencies(inputPath, components);
143 |
144 | // Add CSS to bundle
145 | this.config.javascriptFunctions.css(css, "default", data.page.url);
146 |
147 | if(buckets.css) {
148 | for(let bucket in buckets.css) {
149 | this.config.javascriptFunctions.css(buckets.css[bucket], bucket, data.page.url);
150 | }
151 | }
152 |
153 | // Add JS to bundle
154 | this.config.javascriptFunctions.js(js, "default", data.page.url);
155 |
156 | if(buckets.js) {
157 | for(let bucket in buckets.js) {
158 | this.config.javascriptFunctions.js(buckets.js[bucket], bucket, data.page.url);
159 | }
160 | }
161 |
162 | return html;
163 | };
164 | }
165 | });
166 | };
167 |
--------------------------------------------------------------------------------
/test/test.mjs:
--------------------------------------------------------------------------------
1 | import test from "ava";
2 | import Eleventy from "@11ty/eleventy";
3 |
4 | import { createRequire } from "node:module";
5 | const require = createRequire(import.meta.url);
6 | const pkg = require("../package.json");
7 |
8 | function normalize(str) {
9 | return str.trim().replace(/\r\n/g, "\n");
10 | }
11 |
12 | test("Sample page (webc layout)", async t => {
13 | let elev = new Eleventy("./test/sample-1/page.webc", "./test/sample-1/_site", {
14 | configPath: "./test/sample-1/eleventy.config.js"
15 | });
16 |
17 | let results = await elev.toJSON();
18 | let [result] = results;
19 |
20 | t.is(normalize(result.content), `
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | WHO IS THIS
34 | hi
35 | HELLO FROM FRONT MATTER
36 |
37 |
38 |
39 |
40 |
41 | `);
42 | });
43 |
44 | test("Sample page (liquid layout and one webc component)", async t => {
45 | let elev = new Eleventy("./test/sample-non-webc-layout/page.webc", "./test/sample-non-webc-layout/_site", {
46 | configPath: "./test/sample-non-webc-layout/eleventy.config.js"
47 | });
48 |
49 | let results = await elev.toJSON();
50 | let [result] = results;
51 |
52 | t.is(normalize(result.content), `
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | HELLO
64 |
65 | HELLO
66 |
67 | WHO IS THIS
68 | hi
69 | HELLO FROM FRONT MATTER
70 |
71 |
72 |
73 |
74 | `);
75 | });
76 |
77 | test("Sample page with global component", async t => {
78 | let elev = new Eleventy("./test/sample-2/page.webc", "./test/sample-2/_site", {
79 | configPath: "./test/sample-2/eleventy.config.js"
80 | });
81 |
82 | let results = await elev.toJSON();
83 | let [result] = results;
84 |
85 | t.is(normalize(result.content), `
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | This is a component.
97 | This is a component.
98 | WHO IS THIS
99 | hi
100 | HELLO FROM FRONT MATTER
101 |
102 |
103 |
104 |
105 |
106 | `);
107 | });
108 |
109 | test("Page with front matter no-import components", async t => {
110 | let elev = new Eleventy("./test/sample-page-global-components/page.webc", "./test/sample-page-global-components/_site", {
111 | configPath: "./test/sample-page-global-components/eleventy.config.js"
112 | });
113 |
114 | let results = await elev.toJSON();
115 | let [result] = results;
116 |
117 | t.is(normalize(result.content), `
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | HELLO
129 | HELLO
130 | WHO IS THIS
131 | hi
132 | HELLO FROM FRONT MATTER
133 |
134 |
135 |
136 |
137 |
138 | `);
139 | });
140 |
141 |
142 | test("Page with front matter no-import components (relative to input path)", async t => {
143 | let elev = new Eleventy("./test/sample-page-global-components-relative-to-inputpath/page.webc", "./test/sample-page-global-components-relative-to-inputpath/_site", {
144 | configPath: "./test/sample-page-global-components-relative-to-inputpath/eleventy.config.js"
145 | });
146 |
147 | let results = await elev.toJSON();
148 | let [result] = results;
149 |
150 | t.is(normalize(result.content), `
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 | HELLO
162 | HELLO
163 | WHO IS THIS
164 | hi
165 | HELLO FROM FRONT MATTER
166 |
167 |
168 |
169 |
170 |
171 | `);
172 | });
173 |
174 | test("WebC using a transform", async t => {
175 | let elev = new Eleventy("./test/sample-transform/", "./test/sample-transform/_site", {
176 | configPath: "./test/sample-transform/eleventy.config.js"
177 | });
178 |
179 | let results = await elev.toJSON();
180 | let [result] = results;
181 |
182 | t.is(normalize(result.content), `HELLO${pkg.version}
183 | HELLO${pkg.version}
184 | WHO IS THIS
185 | hi
186 | HELLO FROM FRONT MATTER`);
187 | });
188 |
189 | test("WebC using htmlTemplateEngine", async t => {
190 | let elev = new Eleventy("./test/sample-html-preprocess/", "./test/sample-html-preprocess/_site", {
191 | configPath: "./test/sample-html-preprocess/eleventy.config.js"
192 | });
193 |
194 | let results = await elev.toJSON();
195 | let [result] = results;
196 |
197 | t.is(normalize(result.content), `HELLO${pkg.version}
198 | HELLO${pkg.version}
199 | WHO IS THIS
200 | hi`);
201 | });
202 |
203 | test("Sample page with permalink: false (issue #9)", async t => {
204 | let elev = new Eleventy("./test/sample-permalink-false/", "./test/sample-permalink-false/_site", {
205 | configPath: "./test/sample-permalink-false/eleventy.config.js"
206 | });
207 |
208 | let results = await elev.toJSON();
209 | let [result] = results;
210 |
211 | t.is(normalize(result.content), `
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | `);
223 | });
224 |
225 | test("Sample WebC page with permalink: false (issue #86)", async t => {
226 | let elev = new Eleventy("./test/sample-permalink-false-webc/", "./test/sample-permalink-false-webc/_site", {
227 | configPath: "./test/sample-permalink-false-webc/eleventy.config.js"
228 | });
229 |
230 | let results = await elev.toJSON();
231 | let [result] = results;
232 |
233 | t.is(normalize(result.content), `
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 | `);
244 | });
245 |
246 | test("Add JS Functions as helpers (universal filters) (issue #3)", async t => {
247 | let elev = new Eleventy("./test/sample-universal-helpers/", "./test/sample-universal-helpers/_site", {
248 | configPath: "./test/sample-universal-helpers/eleventy.config.js"
249 | });
250 |
251 | let results = await elev.toJSON();
252 | let [result] = results;
253 |
254 | t.is(normalize(result.content), `
255 |
256 |
257 |
258 |
259 | helloAlways return this/page/
260 | `);
261 | });
262 |
263 | test("Use render plugin #22", async t => {
264 | let elev = new Eleventy("./test/render-plugin/page.md", "./test/render-plugin/_site", {
265 | configPath: "./test/render-plugin/eleventy.config.mjs"
266 | });
267 |
268 | let results = await elev.toJSON();
269 | let [result] = results;
270 |
271 | t.is(normalize(result.content), `Hello
272 | My component
`);
273 | });
274 |
275 | test("UID leftovers #17", async t => {
276 | let elev = new Eleventy("./test/uid-leftovers/page.webc", "./test/uid-leftovers/_site", {
277 | configPath: "./test/uid-leftovers/eleventy.config.js"
278 | });
279 |
280 | await elev.toJSON();
281 |
282 | let results = await elev.toJSON();
283 | let [result] = results;
284 |
285 | t.is(normalize(result.content), `
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 | `);
294 | });
295 |
296 | test("Custom permalink JS, issue #27", async t => {
297 | let elev = new Eleventy("./test/custom-permalink/page.webc", "./test/custom-permalink/_site", {
298 | configPath: "./test/custom-permalink/eleventy.config.js"
299 | });
300 |
301 | let results = await elev.toJSON();
302 | let [result] = results;
303 |
304 | t.is(result.url, "/hello-from-front-matter.html")
305 | t.is(normalize(result.content), `
306 |
307 | WHO IS THIS
308 | hi
309 | HELLO FROM FRONT MATTER`);
310 | });
311 |
312 | test("Raw layout html to re-enable reprocessing mode in layouts, issue #20", async t => {
313 | let elev = new Eleventy("./test/raw-layout-html/page.webc", "./test/raw-layout-html/_site", {
314 | configPath: "./test/raw-layout-html/eleventy.config.js"
315 | });
316 |
317 | let results = await elev.toJSON();
318 | let [result] = results;
319 | t.is(normalize(result.content), `
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 | Using raw here to test reprocessing in the layout
330 |
331 | Using raw here to test reprocessing in the layout
332 |
333 | WHO IS THIS
334 | hi
335 | HELLO FROM FRONT MATTER
336 | REPROCESSED
337 |
338 |
339 | `);
340 | });
341 |
342 |
343 | test("Shortcodes, issue #16", async t => {
344 | let elev = new Eleventy("./test/shortcodes-issue-16/page.webc", "./test/shortcodes-issue-16/_site", {
345 | configPath: "./test/shortcodes-issue-16/eleventy.config.js"
346 | });
347 |
348 | let results = await elev.toJSON();
349 | let [result] = results;
350 | t.is(normalize(result.content), `HELLO FROM FRONT MATTER
351 | COMPONENTS DIR
352 | LOWERCASE`);
353 | });
354 |
355 | test("Nested layouts", async t => {
356 | let elev = new Eleventy("./test/nested-layouts/page.webc", "./test/nested-layouts/_site", {
357 | configPath: "./test/nested-layouts/eleventy.config.js"
358 | });
359 |
360 | let results = await elev.toJSON();
361 | let [result] = results;
362 | t.is(normalize(result.content), `
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 | Base
373 | Testing
374 |
375 |
376 |
377 |
378 | `);
379 | });
380 |
381 | test("Components in layouts #11", async t => {
382 | let elev = new Eleventy("./test/components-in-layouts/", "./test/components-in-layouts/_site", {
383 | configPath: "./test/components-in-layouts/eleventy.config.js"
384 | });
385 |
386 | let results = await elev.toJSON();
387 | let [page1] = results.filter(page => page.inputPath.endsWith("page1.webc"));
388 | let [page2] = results.filter(page => page.inputPath.endsWith("page2.webc"));
389 | let [page3] = results.filter(page => page.inputPath.endsWith("page3.webc"));
390 |
391 | t.is(normalize(page1.content), `
392 |
393 |
394 |
395 |
396 |
397 |
398 |
400 |
401 |
402 | Page
403 | Test
404 |
405 | Test
406 |
407 |
408 |
409 | `);
410 |
411 | t.is(normalize(page2.content), `
412 |
413 |
414 |
415 |
416 |
417 |
418 |
420 |
421 |
422 | Other page
423 | Test
424 |
425 | Test
426 |
427 |
428 |
429 | `);
430 |
431 | t.is(normalize(page3.content), `No layouts here
432 |
433 | Test
434 | `);
435 | });
436 |
437 |
438 | test("Helpers in the bundler", async t => {
439 | let elev = new Eleventy("./test/bundler-helpers/index.webc", "./test/bundler-helpers/_site", {
440 | configPath: "./test/bundler-helpers/eleventy.config.js"
441 | });
442 |
443 | let results = await elev.toJSON();
444 | let [result] = results;
445 |
446 | t.is(normalize(result.content), `
448 | `);
450 | });
451 |
452 | test("page with `javascript` front matter", async t => {
453 | let elev = new Eleventy("./test/custom-js-front-matter/", "./test/custom-js-front-matter/_site", {
454 | configPath: "./test/custom-js-front-matter/eleventy.config.js"
455 | });
456 |
457 | let results = await elev.toJSON();
458 | let [result] = results;
459 |
460 | t.is(normalize(result.content), `HELLO FROM FRONT MATTER`);
461 | });
462 |
463 | test("Custom permalink JS, issue #32", async t => {
464 | let elev = new Eleventy("./test/custom-permalink-issue-32/page.webc", "./test/custom-permalink-issue-32/_site", {
465 | configPath: "./test/custom-permalink-issue-32/eleventy.config.js"
466 | });
467 |
468 | let results = await elev.toJSON();
469 | let [result] = results;
470 |
471 | t.is(result.url, "/page.html")
472 | });
473 |
474 | // waiting on https://github.com/11ty/eleventy/issues/2823
475 | // ref: https://github.com/11ty/eleventy-plugin-webc/issues/32#issuecomment-1440831590
476 | test("Custom permalink JS, `dynamicPermalink: false` issue #32", async t => {
477 | let elev = new Eleventy("./test/custom-permalink-not-dynamic-issue-32/page.webc", "./test/custom-permalink-not-dynamic-issue-32/_site", {
478 | configPath: "./test/custom-permalink-not-dynamic-issue-32/eleventy.config.js"
479 | });
480 |
481 | let results = await elev.toJSON();
482 | let [result] = results;
483 |
484 | t.is(result.url, "/page.html")
485 | });
486 |
487 | test("WebC components in liquid layout, issue #35", async t => {
488 | let elev = new Eleventy("./test/webc-component-in-layout/page.liquid", "./test/webc-component-in-layout/_site", {
489 | configPath: "./test/webc-component-in-layout/eleventy.config.mjs"
490 | });
491 |
492 | let results = await elev.toJSON();
493 | let [result] = results;
494 |
495 | t.is(normalize(result.content), `
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 | Hello
506 |
507 | `);
508 | });
509 |
510 | test("Permalink string, issue #52", async t => {
511 | let elev = new Eleventy("./test/permalink-string/", "./test/permalink-string/_site", {
512 | configPath: "./test/permalink-string/eleventy.config.js"
513 | });
514 |
515 | let results = await elev.toJSON();
516 | let [result1, result2] = results.sort((a, b) => a.inputPath < b.inputPath ? -1 : 1);
517 |
518 | t.is(result1.url, "/");
519 | t.is(result2.url, "/index2.html");
520 | });
521 |
522 | test("Using file system bundles, issue #4", async t => {
523 | let elev = new Eleventy("./test/bundler-to-file/", "./test/bundler-to-file/_site", {
524 | configPath: "./test/generic.eleventy.config.js"
525 | });
526 |
527 | let [result] = await elev.toJSON();
528 | t.is(normalize(result.content), ``);
529 |
530 | // TODO test actual file output when https://github.com/11ty/eleventy-plugin-bundle/issues/4 is fixed
531 | // let [ passthroughCopy, results ] = await elev.write();
532 | // let [ result ] = results;
533 | // t.is(normalize(result.content), ``);
534 |
535 | // fs.unlinkSync("./test/bundler-to-file/_site/index.html")
536 | // fs.rmdirSync("./test/bundler-to-file/_site/")
537 | });
538 |
539 | test("Page with bundled scripts and styles from components", async (t) => {
540 | let elev = new Eleventy(
541 | "./test/script-and-style-buckets/page.webc",
542 | "./test/script-and-style-buckets/_site",
543 | {
544 | configPath: "./test/script-and-style-buckets/eleventy.config.mjs",
545 | }
546 | );
547 |
548 | let results = await elev.toJSON();
549 | let [result] = results;
550 |
551 | t.is(
552 | normalize(result.content),
553 | `
554 |
555 |
556 |
557 |
558 |
559 |
560 |
563 |
564 |
565 |
566 | Hello everyone!
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 | `
578 | );
579 | });
580 |
--------------------------------------------------------------------------------