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 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>&copy; {{ 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)
@@ -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
+ }