eleventy-plugin-edgejs 1.0.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.
- package/LICENSE +21 -0
- package/README.md +291 -0
- package/edgeJsPlugin.js +67 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Neal
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
# eleventy-plugin-edgejs
|
|
2
|
+
|
|
3
|
+
An [Eleventy](https://www.11ty.dev/) plugin that adds support for [Edge.js](https://edgejs.dev/) templates. Edge.js is a modern, async-first templating engine from the AdonisJS team.
|
|
4
|
+
|
|
5
|
+
Requires Eleventy v3.0.0+ and Node.js 22+.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install eleventy-plugin-edgejs
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
Register the plugin in your Eleventy config file:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import edgeJsPlugin from "eleventy-plugin-edgejs";
|
|
19
|
+
|
|
20
|
+
export default function ( eleventyConfig ) {
|
|
21
|
+
eleventyConfig.addPlugin( edgeJsPlugin );
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Create `.edge` files in your project and they'll be processed by Edge.js automatically.
|
|
26
|
+
|
|
27
|
+
### Plugin Options
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
eleventyConfig.addPlugin( edgeJsPlugin, {
|
|
31
|
+
// Enable template caching (default: false)
|
|
32
|
+
cache: false,
|
|
33
|
+
|
|
34
|
+
// Provide your own Edge.js instance
|
|
35
|
+
eleventyLibraryOverride: undefined,
|
|
36
|
+
|
|
37
|
+
// Register global variables available in all templates
|
|
38
|
+
globals: {
|
|
39
|
+
siteName: "My Site"
|
|
40
|
+
}
|
|
41
|
+
} );
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Filters and Shortcodes
|
|
45
|
+
|
|
46
|
+
Eleventy universal filters and shortcodes are automatically bridged into Edge.js templates as global functions. Edge.js does not use a pipe syntax for filters — instead, call them as functions:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
// eleventy.config.js
|
|
50
|
+
eleventyConfig.addFilter( "upcase", ( str ) => str.toUpperCase() );
|
|
51
|
+
eleventyConfig.addShortcode( "year", () => `${ new Date().getFullYear() }` );
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
```edge
|
|
55
|
+
{{-- In your .edge template --}}
|
|
56
|
+
<p>{{ upcase( name ) }}</p>
|
|
57
|
+
<p>© {{ year() }}</p>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Paired shortcodes also work as globals. The content is passed as the first argument.
|
|
61
|
+
|
|
62
|
+
## Edge.js Template Syntax
|
|
63
|
+
|
|
64
|
+
### Variable Interpolation
|
|
65
|
+
|
|
66
|
+
Use double curly braces for escaped output and triple curly braces for raw (unescaped) output:
|
|
67
|
+
|
|
68
|
+
```edge
|
|
69
|
+
{{ title }}
|
|
70
|
+
{{{ rawHtml }}}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Conditionals
|
|
74
|
+
|
|
75
|
+
```edge
|
|
76
|
+
@if( user.isAdmin )
|
|
77
|
+
<p>Welcome, admin!</p>
|
|
78
|
+
@elseif( user.isMember )
|
|
79
|
+
<p>Welcome, member!</p>
|
|
80
|
+
@else
|
|
81
|
+
<p>Welcome, guest!</p>
|
|
82
|
+
@end
|
|
83
|
+
|
|
84
|
+
@unless( isLoggedIn )
|
|
85
|
+
<p>Please log in.</p>
|
|
86
|
+
@end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Ternary expressions work inline:
|
|
90
|
+
|
|
91
|
+
```edge
|
|
92
|
+
<p>{{ isActive ? "Active" : "Inactive" }}</p>
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Loops
|
|
96
|
+
|
|
97
|
+
```edge
|
|
98
|
+
@each( item in items )
|
|
99
|
+
<li>{{ item }}</li>
|
|
100
|
+
@end
|
|
101
|
+
|
|
102
|
+
{{-- With index --}}
|
|
103
|
+
@each( ( item, index ) in items )
|
|
104
|
+
<li>{{ index }}: {{ item }}</li>
|
|
105
|
+
@end
|
|
106
|
+
|
|
107
|
+
{{-- Loop over object entries --}}
|
|
108
|
+
@each( ( value, key ) in object )
|
|
109
|
+
<dt>{{ key }}</dt>
|
|
110
|
+
<dd>{{ value }}</dd>
|
|
111
|
+
@end
|
|
112
|
+
|
|
113
|
+
{{-- Empty fallback --}}
|
|
114
|
+
@each( item in items )
|
|
115
|
+
<li>{{ item }}</li>
|
|
116
|
+
@else
|
|
117
|
+
<li>No items found.</li>
|
|
118
|
+
@end
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Variables
|
|
122
|
+
|
|
123
|
+
Declare or reassign variables within a template:
|
|
124
|
+
|
|
125
|
+
```edge
|
|
126
|
+
@let( greeting = "Hello" )
|
|
127
|
+
<p>{{ greeting }}, World!</p>
|
|
128
|
+
|
|
129
|
+
@assign( greeting = "Hi" )
|
|
130
|
+
<p>{{ greeting }}, World!</p>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Includes
|
|
134
|
+
|
|
135
|
+
Include partial templates from your `_includes` directory. Edge.js `@` tags must be on their own line:
|
|
136
|
+
|
|
137
|
+
```edge
|
|
138
|
+
<header>
|
|
139
|
+
@include( 'nav' )
|
|
140
|
+
</header>
|
|
141
|
+
|
|
142
|
+
{{-- Conditional include (renders only when condition is truthy) --}}
|
|
143
|
+
@includeIf( showSidebar, 'sidebar' )
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Components and Slots
|
|
147
|
+
|
|
148
|
+
Components live in `_includes/components/`. They provide a powerful alternative to template inheritance.
|
|
149
|
+
|
|
150
|
+
A component file (`_includes/components/card.edge`):
|
|
151
|
+
|
|
152
|
+
```edge
|
|
153
|
+
<div class="card">
|
|
154
|
+
<div class="card-body">{{{ await $slots.main() }}}</div>
|
|
155
|
+
</div>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Using the component:
|
|
159
|
+
|
|
160
|
+
```edge
|
|
161
|
+
@component( 'components/card' )
|
|
162
|
+
<p>This goes into the main slot.</p>
|
|
163
|
+
@end
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
#### Named Slots
|
|
167
|
+
|
|
168
|
+
A component with multiple slots (`_includes/components/modal.edge`):
|
|
169
|
+
|
|
170
|
+
```edge
|
|
171
|
+
<div class="modal">
|
|
172
|
+
<header>{{{ await $slots.header() }}}</header>
|
|
173
|
+
<main>{{{ await $slots.main() }}}</main>
|
|
174
|
+
@if( $slots.footer )
|
|
175
|
+
<footer>{{{ await $slots.footer() }}}</footer>
|
|
176
|
+
@end
|
|
177
|
+
</div>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Using named slots:
|
|
181
|
+
|
|
182
|
+
```edge
|
|
183
|
+
@component( 'components/modal' )
|
|
184
|
+
@slot( 'header' )
|
|
185
|
+
<h2>Modal Title</h2>
|
|
186
|
+
@end
|
|
187
|
+
|
|
188
|
+
@slot( 'main' )
|
|
189
|
+
<p>Modal content goes here.</p>
|
|
190
|
+
@end
|
|
191
|
+
|
|
192
|
+
@slot( 'footer' )
|
|
193
|
+
<button>Close</button>
|
|
194
|
+
@end
|
|
195
|
+
@end
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
#### Component Props
|
|
199
|
+
|
|
200
|
+
Pass data to components as attributes:
|
|
201
|
+
|
|
202
|
+
```edge
|
|
203
|
+
{{-- _includes/components/button.edge --}}
|
|
204
|
+
<button class="{{ type }}">{{ text }}</button>
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
```edge
|
|
208
|
+
@component( 'components/button', { type: 'primary', text: 'Click me' } )
|
|
209
|
+
@end
|
|
210
|
+
|
|
211
|
+
{{-- Self-closing form --}}
|
|
212
|
+
@!component( 'components/button', { type: 'danger', text: 'Delete' } )
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Comments
|
|
216
|
+
|
|
217
|
+
Edge.js comments are stripped from the output:
|
|
218
|
+
|
|
219
|
+
```edge
|
|
220
|
+
{{-- This comment will not appear in the HTML --}}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Escaping Edge Syntax
|
|
224
|
+
|
|
225
|
+
Prefix `@` to output curly braces literally:
|
|
226
|
+
|
|
227
|
+
```edge
|
|
228
|
+
@{{ this will not be interpreted }}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Built-in Helpers
|
|
232
|
+
|
|
233
|
+
Edge.js includes several built-in helpers:
|
|
234
|
+
|
|
235
|
+
```edge
|
|
236
|
+
{{-- CSS class builder --}}
|
|
237
|
+
<div class="{{ html.classNames( { active: isActive, hidden: !isVisible } ) }}"></div>
|
|
238
|
+
|
|
239
|
+
{{-- Truncate text --}}
|
|
240
|
+
<p>{{ truncate( longText, 20 ) }}</p>
|
|
241
|
+
|
|
242
|
+
{{-- Convert newlines to <br> tags --}}
|
|
243
|
+
{{{ nl2br( multiLineText ) }}}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Newline Suppression
|
|
247
|
+
|
|
248
|
+
Use `~` to remove trailing newlines from tag output:
|
|
249
|
+
|
|
250
|
+
```edge
|
|
251
|
+
@if( show )~
|
|
252
|
+
content
|
|
253
|
+
@end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Layouts
|
|
257
|
+
|
|
258
|
+
Use Eleventy's built-in layout system with `.edge` files. Set the layout in front matter:
|
|
259
|
+
|
|
260
|
+
```edge
|
|
261
|
+
---
|
|
262
|
+
layout: layout.edge
|
|
263
|
+
title: My Page
|
|
264
|
+
---
|
|
265
|
+
<h1>{{ title }}</h1>
|
|
266
|
+
<p>Page content here.</p>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
In your layout file (`_includes/layout.edge`):
|
|
270
|
+
|
|
271
|
+
```edge
|
|
272
|
+
<!DOCTYPE html>
|
|
273
|
+
<html>
|
|
274
|
+
<head>
|
|
275
|
+
<title>{{ title }}</title>
|
|
276
|
+
</head>
|
|
277
|
+
<body>
|
|
278
|
+
@include( 'nav' )
|
|
279
|
+
<main>{{{ content }}}</main>
|
|
280
|
+
</body>
|
|
281
|
+
</html>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Further Reading
|
|
285
|
+
|
|
286
|
+
- [Edge.js documentation](https://edgejs.dev/)
|
|
287
|
+
- [Eleventy custom template languages](https://www.11ty.dev/docs/languages/custom/)
|
|
288
|
+
|
|
289
|
+
## License
|
|
290
|
+
|
|
291
|
+
[MIT](./LICENSE)
|
package/edgeJsPlugin.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Edge } from "edge.js";
|
|
2
|
+
|
|
3
|
+
export default function edgeJsPlugin( eleventyConfig, options = {} ) {
|
|
4
|
+
eleventyConfig.versionCheck( ">=3.0.0" );
|
|
5
|
+
|
|
6
|
+
options = Object.assign(
|
|
7
|
+
{
|
|
8
|
+
cache: false,
|
|
9
|
+
eleventyLibraryOverride: undefined,
|
|
10
|
+
globals: {}
|
|
11
|
+
},
|
|
12
|
+
options || {}
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
eleventyConfig.addTemplateFormats( "edge" );
|
|
16
|
+
|
|
17
|
+
// Create Edge instance eagerly so it's available for permalink compilation
|
|
18
|
+
let edge = options.eleventyLibraryOverride || Edge.create( { cache: options.cache } );
|
|
19
|
+
|
|
20
|
+
// Bridge Eleventy filters as Edge globals
|
|
21
|
+
for ( let [ name, callback ] of Object.entries( eleventyConfig.getFilters() ) ) {
|
|
22
|
+
edge.global( name, callback );
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Bridge Eleventy shortcodes as Edge globals
|
|
26
|
+
for ( let [ name, callback ] of Object.entries( eleventyConfig.getShortcodes() ) ) {
|
|
27
|
+
edge.global( name, callback );
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Bridge Eleventy paired shortcodes as Edge globals
|
|
31
|
+
// Content is passed as the first argument, matching the Handlebars plugin pattern
|
|
32
|
+
for ( let [ name, callback ] of Object.entries( eleventyConfig.getPairedShortcodes() ) ) {
|
|
33
|
+
edge.global( name, callback );
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Register user-provided globals
|
|
37
|
+
for ( let [ name, value ] of Object.entries( options.globals ) ) {
|
|
38
|
+
edge.global( name, value );
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
eleventyConfig.addExtension( "edge", {
|
|
42
|
+
init: async function () {
|
|
43
|
+
// Mount _includes directory for @include/@component support
|
|
44
|
+
let includesDir = this.config.directories?.includes;
|
|
45
|
+
if ( includesDir ) {
|
|
46
|
+
edge.mount( new URL( includesDir, `file://${ process.cwd() }/` ) );
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
compile: ( str ) => {
|
|
51
|
+
return async ( data ) => {
|
|
52
|
+
return edge.renderRaw( str, data );
|
|
53
|
+
};
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
compileOptions: {
|
|
57
|
+
permalink: ( contents ) => {
|
|
58
|
+
if ( typeof contents === "string" ) {
|
|
59
|
+
return async ( data ) => {
|
|
60
|
+
return edge.renderRaw( contents, data );
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return contents;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
} );
|
|
67
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "eleventy-plugin-edgejs",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Eleventy plugin for Edge.js templating",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "edgeJsPlugin.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./edgeJsPlugin.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"edgeJsPlugin.js"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build:example": "npx @11ty/eleventy --input=example/src --config=example/eleventy.config.js",
|
|
15
|
+
"lint": "eslint . --fix",
|
|
16
|
+
"start:example": "npx @11ty/eleventy --input=example/src --config=example/eleventy.config.js --serve",
|
|
17
|
+
"test": "node --test"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"eleventy",
|
|
21
|
+
"eleventy-plugin",
|
|
22
|
+
"edge",
|
|
23
|
+
"edgejs",
|
|
24
|
+
"template-engine"
|
|
25
|
+
],
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22.0.0"
|
|
28
|
+
},
|
|
29
|
+
"author": "David Neal <david@reverentgeek.com> (https://reverentgeek.com)",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/reverentgeek/eleventy-plugin-edgejs"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/reverentgeek/eleventy-plugin-edgejs/issues"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/reverentgeek/eleventy-plugin-edgejs#readme",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"edge.js": "^6.2.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@11ty/eleventy": "^3.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@11ty/eleventy": "^3.0.0",
|
|
47
|
+
"eslint": "^10.0.2",
|
|
48
|
+
"eslint-config-reverentgeek": "^7.0.3"
|
|
49
|
+
}
|
|
50
|
+
}
|