@11ty/eleventy-plugin-webc 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,7 +15,7 @@ module.exports = function(eleventyConfig, options = {}) {
15
15
  }, options.filters);
16
16
 
17
17
  options = Object.assign({
18
- components: false, // glob for no-import global components
18
+ components: "_components/**/*.webc", // glob for no-import global components
19
19
  useTransform: false, // global transform
20
20
  transformData: {}, // extra global data for transforms specifically
21
21
  }, options);
@@ -25,7 +25,12 @@ module.exports = function(eleventyConfig, options = {}) {
25
25
  if(options.components) {
26
26
  eleventyConfig.addWatchTarget(options.components);
27
27
 
28
- // TODO add to eleventy ignores (if not in _includes folder)
28
+ // Opt-out of Eleventy to process components
29
+ // Note that Eleventy’s default ignores already have _includes/**
30
+
31
+ // This will cause component files outside of _includes to not be watched: https://github.com/11ty/eleventy-plugin-webc/issues/29
32
+ // Fixed in @11ty/eleventy@2.0.0-canary.18: https://github.com/11ty/eleventy/issues/893
33
+ eleventyConfig.ignores.add(options.components);
29
34
  }
30
35
 
31
36
  templatePlugin(eleventyConfig, options);
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@11ty/eleventy-plugin-webc",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "WebC support for Eleventy adds for Single File Web Components",
5
5
  "main": "eleventyWebcPlugin.js",
6
6
  "scripts": {
7
- "test": "npx ava"
7
+ "test": "npx ava --no-worker-threads"
8
8
  },
9
9
  "publishConfig": {
10
10
  "access": "public"
@@ -14,7 +14,7 @@
14
14
  "node": ">=14.18"
15
15
  },
16
16
  "11ty": {
17
- "compatibility": ">=2.0.0-canary.16"
17
+ "compatibility": ">=2.0.0-canary.17"
18
18
  },
19
19
  "funding": {
20
20
  "type": "opencollective",
@@ -38,8 +38,8 @@
38
38
  ]
39
39
  },
40
40
  "dependencies": {
41
- "@11ty/eleventy": "^2.0.0-canary.16",
42
- "@11ty/webc": "^0.6.0"
41
+ "@11ty/eleventy": "^2.0.0-canary.18",
42
+ "@11ty/webc": "^0.8.0"
43
43
  },
44
44
  "devDependencies": {
45
45
  "ava": "^5.0.1"
@@ -0,0 +1,50 @@
1
+ class BundleAssetsToContent {
2
+ static SPLIT_REGEX = /(\/\*__WebC:[^:]*:[^:]*:WebC__\*\/)/;
3
+ static SEPARATOR = ":";
4
+
5
+ constructor(content) {
6
+ this.content = content;
7
+ this.managers = {};
8
+ }
9
+
10
+ static getAssetKey(name, bucket) {
11
+ return `/*__WebC:${name}:${bucket || "default"}:WebC__*/`
12
+ }
13
+
14
+ setAssetManager(name, assetManager) {
15
+ this.managers[name] = assetManager;
16
+ }
17
+
18
+ normalizeMatch(match) {
19
+ if(match.startsWith("/*__WebC:")) {
20
+ let [prefix, name, bucket, suffix] = match.split(BundleAssetsToContent.SEPARATOR);
21
+ return { name, bucket };
22
+ }
23
+ return match;
24
+ }
25
+
26
+ findAll() {
27
+ let matches = this.content.split(BundleAssetsToContent.SPLIT_REGEX);
28
+ let ret = [];
29
+ for(let match of matches) {
30
+ ret.push(this.normalizeMatch(match));
31
+ }
32
+ return ret;
33
+ }
34
+
35
+ replaceAll(url) {
36
+ let matches = this.findAll();
37
+ return matches.map(match => {
38
+ if(typeof match === "string") {
39
+ return match;
40
+ }
41
+ let {name, bucket} = match;
42
+ if(!this.managers[name]) {
43
+ throw new Error(`No asset manager found for ${name}. Known keys: ${Object.keys(this.managers)}`);
44
+ }
45
+ return this.managers[name].getForPage(url, bucket);
46
+ }).join("");
47
+ }
48
+ }
49
+
50
+ module.exports = BundleAssetsToContent;
@@ -1,10 +1,11 @@
1
1
  const path = require("path");
2
2
 
3
3
  const { EleventyRenderPlugin } = require("@11ty/eleventy");
4
- const EleventyRenderManager = EleventyRenderPlugin.RenderManager;
4
+ const CompileString = EleventyRenderPlugin.String;
5
5
 
6
6
  const CodeManager = require("./codeManager.js");
7
7
  const WebCIncremental = require("./incremental.js");
8
+ const BundleAssetsToContent = require("./bundleAssets.js");
8
9
 
9
10
  function relativePath(inputPath, newGlob) {
10
11
  // project root
@@ -22,19 +23,20 @@ function relativePath(inputPath, newGlob) {
22
23
  module.exports = function(eleventyConfig, options = {}) {
23
24
  eleventyConfig.addTemplateFormats("webc");
24
25
 
25
- let renderManager = new EleventyRenderManager();
26
26
  let cssManager = new CodeManager();
27
27
  let jsManager = new CodeManager();
28
28
  let incremental = new WebCIncremental();
29
29
  let componentsMap = false; // cache the glob search
30
30
  let componentsMapKey;
31
+ let moduleScript;
31
32
 
32
33
  eleventyConfig.on("eleventy.before", async () => {
33
34
  cssManager.reset();
34
35
  jsManager.reset();
35
36
 
36
37
  // For ESM in CJS
37
- let { WebC } = await import("@11ty/webc");
38
+ let { WebC, ModuleScript } = await import("@11ty/webc");
39
+ moduleScript = ModuleScript;
38
40
  incremental.setWebC(WebC);
39
41
 
40
42
  if(options.components) {
@@ -43,18 +45,21 @@ module.exports = function(eleventyConfig, options = {}) {
43
45
  }
44
46
  });
45
47
 
46
- function getCss(pageUrl, bucket = "default") {
47
- return cssManager.getForPage(pageUrl, bucket);
48
- }
49
-
50
- function getJs(pageUrl, bucket = "default") {
51
- return jsManager.getForPage(pageUrl, bucket);
52
- }
53
-
48
+ // Expose bundled CSS code to other template languages
54
49
  if(options.filters.css) {
50
+ function getCss(pageUrl, bucket = "default") {
51
+ return cssManager.getForPage(pageUrl, bucket);
52
+ }
53
+
55
54
  eleventyConfig.addFilter(options.filters.css, (url, bucket) => getCss(url, bucket));
56
55
  }
56
+
57
+ // Expose bundled JS code to other template languages
57
58
  if(options.filters.js) {
59
+ function getJs(pageUrl, bucket = "default") {
60
+ return jsManager.getForPage(pageUrl, bucket);
61
+ }
62
+
58
63
  eleventyConfig.addFilter(options.filters.js, (url, bucket) => getJs(url, bucket));
59
64
  }
60
65
 
@@ -67,11 +72,12 @@ module.exports = function(eleventyConfig, options = {}) {
67
72
 
68
73
  isIncrementalMatch: function (incrementalFilePath) {
69
74
  // Eleventy layouts don’t appear directly in the WebC component graph, so we use the `eleventy.layouts` map here
70
- if(incremental.isTemplateUsingLayout(this.inputPath, incrementalFilePath)) {
75
+ if(incremental.isFileUsingLayout(this.inputPath, incrementalFilePath)) {
71
76
  return true;
72
77
  }
73
78
 
74
79
  let {page, setup} = incremental.get(this.inputPath);
80
+
75
81
  if(page && setup) {
76
82
  let components = page.getComponents(setup);
77
83
  if(components.includes(incrementalFilePath)) {
@@ -87,6 +93,14 @@ module.exports = function(eleventyConfig, options = {}) {
87
93
  getCacheKey: function(contents, inputPath) {
88
94
  // if global components change, recompile!
89
95
  return contents + inputPath + componentsMapKey;
96
+ },
97
+ permalink: function(contents, inputPath) {
98
+ return (data) => {
99
+ return moduleScript.evaluateScript("permalink", contents, {
100
+ ...this,
101
+ ...data,
102
+ });
103
+ }
90
104
  }
91
105
  },
92
106
 
@@ -103,28 +117,36 @@ module.exports = function(eleventyConfig, options = {}) {
103
117
  }
104
118
 
105
119
  // Support both casings (I prefer getCss, but yeah)
106
- page.setHelper("getCss", (url, bucket) => getCss(url, bucket));
107
- page.setHelper("getCSS", (url, bucket) => getCss(url, bucket));
120
+ page.setHelper("getCss", (url, bucket) => BundleAssetsToContent.getAssetKey("css", bucket));
121
+ page.setHelper("getCSS", (url, bucket) => BundleAssetsToContent.getAssetKey("css", bucket));
108
122
 
109
- page.setHelper("getJs", (url, bucket) => getJs(url, bucket));
110
- page.setHelper("getJS", (url, bucket) => getJs(url, bucket));
123
+ page.setHelper("getJs", (url, bucket) => BundleAssetsToContent.getAssetKey("js", bucket));
124
+ page.setHelper("getJS", (url, bucket) => BundleAssetsToContent.getAssetKey("js", bucket));
111
125
 
112
126
  page.setTransform("11ty", async function(content) {
113
127
  let syntax = this["11ty:type"];
114
128
  if(syntax) {
115
- let fn = await renderManager.compile(content, syntax);
116
- return renderManager.render(fn, this, {});
129
+ let fn = await CompileString(content, syntax, {
130
+ templateConfig: eleventyConfig
131
+ });
132
+ return fn(this);
117
133
  }
118
134
  return content;
119
135
  });
120
136
 
121
137
  return async (data) => {
122
- let setupObject = { data };
138
+ let setupObject = {
139
+ data,
140
+ };
123
141
  if(data.webc?.components) {
124
142
  let WebC = incremental.webc;
125
143
  setupObject.components = WebC.getComponentsMap(relativePath(data.page.inputPath, data.webc.components));
126
144
  }
127
145
 
146
+ if(options.before && typeof options.before === "function") {
147
+ await options.before(page);
148
+ }
149
+
128
150
  let setup = await page.setup(setupObject);
129
151
  incremental.addSetup(inputPath, setup);
130
152
 
@@ -147,7 +169,14 @@ module.exports = function(eleventyConfig, options = {}) {
147
169
  }
148
170
  }
149
171
 
150
- return html;
172
+ // Always do a two pass render for assets to catch any CSS/JS that were compiled *in* the same template.
173
+ // https://github.com/11ty/eleventy-plugin-webc/issues/33
174
+ // This unlocks use of bundled asset code anywhere in the WebC component tree (not just Eleventy Layouts)
175
+ let bundler = new BundleAssetsToContent(html);
176
+ bundler.setAssetManager("css", cssManager);
177
+ bundler.setAssetManager("js", jsManager);
178
+
179
+ return bundler.replaceAll(data.page.url);
151
180
  };
152
181
  }
153
182
  });
@@ -12,7 +12,7 @@ class WebCIncremental {
12
12
  this.layouts = layouts;
13
13
  }
14
14
 
15
- isTemplateUsingLayout(templateFilePath, layoutFilePath) {
15
+ isFileUsingLayout(templateFilePath, layoutFilePath) {
16
16
  if(this.layouts && this.layouts[layoutFilePath] && this.layouts[layoutFilePath].includes(templateFilePath)) {
17
17
  return true;
18
18
  }
@@ -23,15 +23,7 @@ class WebCIncremental {
23
23
  let WebC = this.webc;
24
24
  let page = new WebC();
25
25
 
26
- // Explicitly disable bundler mode for layouts
27
- if(this.layouts && this.layouts[inputPath]) {
28
- page.setBundlerMode(false);
29
- page.setReprocessingMode(false);
30
- } else {
31
- page.setBundlerMode(true);
32
- page.setReprocessingMode(true);
33
- }
34
-
26
+ page.setBundlerMode(true);
35
27
  page.setContent(inputContent, inputPath);
36
28
 
37
29
  this.pages[inputPath] = page;