eleventy-plugin-edgejs 1.0.0 → 1.1.1
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.
- package/README.md +16 -0
- package/edgeJsPlugin.js +100 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,9 @@ npm install eleventy-plugin-edgejs
|
|
|
12
12
|
|
|
13
13
|
## Usage
|
|
14
14
|
|
|
15
|
+
> [!TIP]
|
|
16
|
+
> This repository includes a working Eleventy site with more template and syntax examples. Browse the [example source](./example) or see the [Example Site](#example-site) section for instructions on running it locally.
|
|
17
|
+
|
|
15
18
|
Register the plugin in your Eleventy config file:
|
|
16
19
|
|
|
17
20
|
```js
|
|
@@ -281,6 +284,19 @@ In your layout file (`_includes/layout.edge`):
|
|
|
281
284
|
</html>
|
|
282
285
|
```
|
|
283
286
|
|
|
287
|
+
## Example Site
|
|
288
|
+
|
|
289
|
+
This repository includes a working Eleventy site with more template and syntax examples. To run it locally:
|
|
290
|
+
|
|
291
|
+
```sh
|
|
292
|
+
git clone https://github.com/reverentgeek/eleventy-plugin-edgejs.git
|
|
293
|
+
cd eleventy-plugin-edgejs
|
|
294
|
+
npm install
|
|
295
|
+
npm run start:example
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
This starts a local dev server so you can browse the examples and experiment with Edge.js templates.
|
|
299
|
+
|
|
284
300
|
## Further Reading
|
|
285
301
|
|
|
286
302
|
- [Edge.js documentation](https://edgejs.dev/)
|
package/edgeJsPlugin.js
CHANGED
|
@@ -1,4 +1,103 @@
|
|
|
1
|
-
import { Edge } from "edge.js";
|
|
1
|
+
import { Edge, Template } from "edge.js";
|
|
2
|
+
|
|
3
|
+
// Sentinel prefix for async placeholders (uses null byte to avoid collisions with real content)
|
|
4
|
+
const ASYNC_PREFIX = "\0__EDGE_ASYNC_";
|
|
5
|
+
const ASYNC_SUFFIX = "__\0";
|
|
6
|
+
const ASYNC_PATTERN = /\0__EDGE_ASYNC_(\d+)__\0/g;
|
|
7
|
+
|
|
8
|
+
// Patch Template.prototype.escape to:
|
|
9
|
+
// 1. Render null/undefined as empty string (matches Nunjucks, Handlebars, Liquid, Mustache)
|
|
10
|
+
// 2. Detect unresolved Promises and defer resolution via placeholders
|
|
11
|
+
const _originalEscape = Template.prototype.escape;
|
|
12
|
+
|
|
13
|
+
Template.prototype.escape = function ( input ) {
|
|
14
|
+
// Convert null/undefined to empty string instead of "null"/"undefined"
|
|
15
|
+
if ( input == null ) return "";
|
|
16
|
+
|
|
17
|
+
// Detect unresolved Promises from async filters/shortcodes
|
|
18
|
+
if ( typeof input === "object" && typeof input.then === "function" ) {
|
|
19
|
+
if ( !this.__pendingPromises ) {
|
|
20
|
+
this.__pendingPromises = [];
|
|
21
|
+
}
|
|
22
|
+
const idx = this.__pendingPromises.length;
|
|
23
|
+
this.__pendingPromises.push( input );
|
|
24
|
+
return `${ ASYNC_PREFIX }${ idx }${ ASYNC_SUFFIX }`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return _originalEscape.call( this, input );
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
// Patch Template.prototype.renderRaw to resolve async placeholders after rendering
|
|
31
|
+
const _originalRenderRaw = Template.prototype.renderRaw;
|
|
32
|
+
|
|
33
|
+
Template.prototype.renderRaw = function ( contents, state, templatePath ) {
|
|
34
|
+
this.__pendingPromises = [];
|
|
35
|
+
|
|
36
|
+
const result = _originalRenderRaw.call( this, contents, state, templatePath );
|
|
37
|
+
|
|
38
|
+
// Async mode returns a Promise
|
|
39
|
+
if ( result && typeof result.then === "function" ) {
|
|
40
|
+
return result.then( output => resolveAsyncPlaceholders( this, output ) );
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Patch Template.prototype.reThrow to preserve the original error as .cause.
|
|
47
|
+
// Edge.js discards the original error class when wrapping in EdgeError, which breaks
|
|
48
|
+
// Eleventy's two-pass rendering system — it can't detect TemplateContentPrematureUseError
|
|
49
|
+
// and fails instead of deferring the template to a second pass.
|
|
50
|
+
const _originalReThrow = Template.prototype.reThrow;
|
|
51
|
+
|
|
52
|
+
Template.prototype.reThrow = function ( error, filename, lineNumber ) {
|
|
53
|
+
try {
|
|
54
|
+
_originalReThrow.call( this, error, filename, lineNumber );
|
|
55
|
+
} catch ( wrapped ) {
|
|
56
|
+
if ( wrapped !== error ) {
|
|
57
|
+
wrapped.cause = error;
|
|
58
|
+
}
|
|
59
|
+
throw wrapped;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Patch Template.prototype.render for includes/components that may also contain async calls
|
|
64
|
+
const _originalRender = Template.prototype.render;
|
|
65
|
+
|
|
66
|
+
Template.prototype.render = function ( template, state ) {
|
|
67
|
+
if ( !this.__pendingPromises ) {
|
|
68
|
+
this.__pendingPromises = [];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = _originalRender.call( this, template, state );
|
|
72
|
+
|
|
73
|
+
if ( result && typeof result.then === "function" ) {
|
|
74
|
+
return result.then( output => resolveAsyncPlaceholders( this, output ) );
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
async function resolveAsyncPlaceholders( template, output ) {
|
|
81
|
+
if ( !template.__pendingPromises || template.__pendingPromises.length === 0 ) {
|
|
82
|
+
return output;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const resolved = await Promise.all( template.__pendingPromises );
|
|
86
|
+
template.__pendingPromises = [];
|
|
87
|
+
|
|
88
|
+
output = output.replace( ASYNC_PATTERN, ( _, idx ) => {
|
|
89
|
+
const val = resolved[parseInt( idx )];
|
|
90
|
+
if ( val == null ) return "";
|
|
91
|
+
return _originalEscape.call( template, val );
|
|
92
|
+
} );
|
|
93
|
+
|
|
94
|
+
// Check if resolving introduced new placeholders (unlikely but possible with nested async)
|
|
95
|
+
if ( ASYNC_PATTERN.test( output ) ) {
|
|
96
|
+
return resolveAsyncPlaceholders( template, output );
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return output;
|
|
100
|
+
}
|
|
2
101
|
|
|
3
102
|
export default function edgeJsPlugin( eleventyConfig, options = {} ) {
|
|
4
103
|
eleventyConfig.versionCheck( ">=3.0.0" );
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eleventy-plugin-edgejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Eleventy plugin for Edge.js templating",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "edgeJsPlugin.js",
|
|
@@ -47,4 +47,4 @@
|
|
|
47
47
|
"eslint": "^10.0.2",
|
|
48
48
|
"eslint-config-reverentgeek": "^7.0.3"
|
|
49
49
|
}
|
|
50
|
-
}
|
|
50
|
+
}
|