Eleventy Edge Added in v2.0.0 Jump to heading
A plugin to run Eleventy in an Edge Function to add dynamic content to your Eleventy sites.
v2.0.0
or higher. Our first release is limited to Netlify Edge Functions support only.Eleventy Edge is an exciting new way to add dynamic content to your Eleventy templates. With a simple Eleventy shortcode you can opt-in a part of your Eleventy template to run on an Edge server, allowing your site to use dynamic, user-specific content!
Here are a few ideas:
- Any user personalized content (User accounts, premium-only content, AB testing)
- Accessing/setting HTTP Headers (e.g. Cookies, Save-Data, Client Hints, etc)
- Handling Forms
- Using Geolocation information to localize content
- A zero-clientside JavaScript Dark mode/Light mode toggle
Try out the demos Jump to heading
- Eleventy Edge demos using Netlify’s Edge Functions.
- Eleventy Edge search on
eleventy-base-blog
with Source code - The template language syntax tabs on this very web site are rendered using the Edge plugin (here’s one small example on this very page). Try saving your template language syntax preference to persist in examples throughout the site. Learn more at
11ty-website/#1462
on GitHub.
How does it work? Jump to heading
If you don’t yet have an Eleventy project, go through the Getting Started Guide first and come back here when you’re done!
1. Installation Jump to heading
The Eleventy Edge plugin is bundled with Eleventy, but do note that the plugin requires version v2.0.0
or newer.
At time of initial launch, you will need to use Netlify CLI to run Eleventy Edge locally (netlify-cli
version 10.0.0
or higher).
npm install netlify-cli
2. Add to your configuration file Jump to heading
const { EleventyEdgePlugin } = require("@11ty/eleventy");
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(EleventyEdgePlugin);
};
Expand to read about the advanced options (you probably don’t need these)
const { EleventyEdgePlugin } = require("@11ty/eleventy");
module.exports = function(eleventyConfig) {
eleventyConfig.addPlugin(EleventyEdgePlugin, {
// controls the shortcode name
name: "edge",
// Used for the default deno import URL
eleventyEdgeVersion: "1.0.0",
// Version check for the Edge runtime
compatibility: ">=2",
// controls where the Edge Function bundles go
functionsDir: "./netlify/edge-functions/",
// Directory to write the import_map.json to
// Also supported: `false`
importMap: "./.netlify/edge-functions/",
});
};
The above plugin will automatically generate an Eleventy Edge Function file for you at: ./netlify/edge-functions/eleventy-edge.js
.
Expand to see a sample Eleventy Edge Function
Note that Edge Functions run in Deno so they require ESM (import
not require
).
import { EleventyEdge, precompiledAppData } from "./_generated/eleventy-edge-app.js";
export default async (request, context) => {
try {
let edge = new EleventyEdge("edge", {
request,
context,
precompiled: precompiledAppData,
// default is [], add more keys to opt-in e.g. ["appearance", "username"]
cookies: [],
});
edge.config(eleventyConfig => {
// Run some more Edge-specific configuration
// e.g. Add a sample filter
eleventyConfig.addFilter("json", obj => JSON.stringify(obj, null, 2));
});
return await edge.handleResponse();
} catch(e) {
console.log( "ERROR", { e } );
return context.next(e);
}
};
Read more about Netlify’s Edge Functions Jump to heading
- Netlify Docs: Edge Functions overview
- Netlify Edge Functions on Deno Deploy
- Netlify Edge Functions: A new serverless runtime powered by Deno
3. Additions to .gitignore
Jump to heading
# Netlify generated stuff
.netlify/
# Eleventy Edge Build Data files
netlify/edge-functions/_generated
4. netlify.toml
Jump to heading
If you don’t already have a netlify.toml
, expand this to view a sample starter.
[dev]
framework = "#static"
command = "npx @11ty/eleventy --quiet --watch"
[build]
command = "npx @11ty/eleventy"
publish = "_site"
Add this to your netlify.toml
file.
[[edge_functions]]
function = "eleventy-edge"
path = "/*"
eleventy-edge
points to the file that was created above at ./netlify/edge-functions/eleventy-edge.js
. Using path= "/*"
will run Eleventy Edge on all of the pages on your site. You can change this setting to something more granular (e.g. path = "/"
for just the home page).
5. Make your content template Jump to heading
Here we are making a simple template file. We can use the {% edge %}
shortcode to run the Liquid template syntax inside on the Edge server.
The content outside of the `edge` shortcode is generated with the Build.
{% edge %}
The content inside of the `edge` shortcode is generated on the Edge.
<pre>
{{ eleventy | json }}
</pre>
{% endedge %}
The content outside of the `edge` shortcode is generated with the Build.
{% edge %}
The content inside of the `edge` shortcode is generated on the Edge.
<pre>
{{ eleventy | dump(2) }}
</pre>
{% endedge %}
module.exports = async function(data) {
return `The content outside of the \`edge\` shortcode is generated with the Build.
${await this.edge(`The content inside of this.edge() is generated on the Edge.
<pre>
{{ eleventy | json }}
</pre>, "liquid")}`;
};
As documented in Limitations, we are using liquid
here because 11ty.js
is not yet supported as an Edge content target.
The edge
shortcode requires an async-friendly template language and is not available in Handlebars.
Learn more about the edge
shortcode.
6. Run your local server Jump to heading
npx netlify dev
Navigation to index.liquid
by going to http://localhost:8888/
in your browser. (Double check your console output to make sure the port is 8888
).
Learn More Jump to heading
Always Escape Input Jump to heading
When using any dynamic user input (via query parameters or cookies), the values here should be treated as potentially malicious user input and you must escape these if you use them in templates. The way to do this is template language specific.
- Liquid has both an
escape
andescape_once
filter. - Nunjucks has autoescape turned on by default. If you’ve disabled it, you can use the
escape
filter. - Read more at the Layouts documentation, which lists both methods for escaped and unescaped output in template languages.
edge
shortcode examples
Jump to heading
Changing the Template Language of the edge
Content
Jump to heading
In what might feel familiar to folks that have used the Render plugin, adding an additional argument to the edge
shortcode allows you to change the content’s template language. If no argument is specified, it uses the template syntax of the parent template.
edge
shortcode inside of a layout file, it’s best to explicitly specify the template language!{% edge "md" %}
# Markdown Heading
{% endedge %}
{% edge "md" %}
# Markdown Heading
{% endedge %}
module.exports = async function(data) {
return `
${await this.edge("# Markdown heading", "md")}
`;
};
The edge
shortcode requires an async-friendly template language and is not available in Handlebars.
Passing Build-time Data to your Edge Function Jump to heading
Edge content is a separate template, processed and built on the Edge. As such it has no access to your build’s data cascade. However, you can pass data in to be re-used!
When the build data argument is a literal (a string or number), it is mapped to _
in the template.
---
name: Zach
---
{% edge "liquid,md" name %}
# Markdown heading for {{ _ }}
{% endedge %}
---
name: Zach
---
{% edge "liquid,md", name %}
# Markdown heading for {{ _ }}
{% endedge %}
module.exports.data = {
name: "Zach",
};
module.exports.render = async function(data) {
return `
${await this.edge("# Markdown heading for {{ _ }}", "liquid,md", data.name)}
`;
};
The edge
shortcode requires an async-friendly template language and is not available in Handlebars.
When the build data argument is an object, the object properties are available as top-level globals in the template.
---
buildData:
name: Zach
---
{% edge "liquid,md" buildData %}
# Markdown heading for {{ name }}
{% endedge %}
---
buildData:
name: Zach
---
{% edge "liquid,md", buildData %}
# Markdown heading for {{ name }}
{% endedge %}
module.exports.data = {
buildData: {
name: "Zach"
}
};
module.exports.render = async function(data) {
return `
${await this.edge("# Markdown heading for {{ name }}", "liquid,md", data.buildData)}
`;
};
The edge
shortcode requires an async-friendly template language and is not available in Handlebars.
Add Global Data to your Edge Function Jump to heading
If you open up your generated netlify/edge-functions/eleventy-edge.js
file, you’ll notice that you are able to run your own arbitrary configuration code on Edge. This means you can run eleventyConfig.addGlobalData
to add your own global data to the edge templates. Any data you add here will automatically be available as a global inside of any {% edge %}
shortcodes without having to pass it as an argument.
import { EleventyEdge, precompiledAppData } from "./_generated/eleventy-edge-app.js";
+import searchData from "./_generated/search-data.js";
export default async (request, context) => {
try {
let edge = new EleventyEdge("edge", {
request,
context,
precompiled: precompiledAppData,
});
edge.config((eleventyConfig) => {
+ eleventyConfig.addGlobalData("search", searchData);
});
return await edge.handleResponse();
} catch (e) {
console.log("ERROR", { e });
return context.next(e);
}
};
Notably, the above adds a search
global from a file we’ve created to populate search data. Now we can reference it in our templates like so:
{% edge "liquid" %}
{{ search | json }}
{% endedge %}
{% edge "liquid" %}
{{ search | json }}
{% endedge %}
module.exports.render = async function(data) {
return `
${await this.edge("{{ search | json }}", "liquid")}
`;
};
Frequently Asked Questions Jump to heading
Limitations Jump to heading
- The
edge
shortcode is only available in async-friendly template languages. Right now that includes:11ty.js
,njk
,liquid
, andmarkdown
(requires another pre-processing language, and the default is Liquid). You can find a bunch of different test cases and examples ondemo-eleventy-edge
- Content inside of the
edge
shortcode (rendered on the Edge) is further limited toliquid
,njk
, ormarkdown
.
How does it compare to Serverless? Jump to heading
They can be used together! Eleventy Edge can be used to process both serverless and build templates. Keep in mind that Edge functions are not cached so if you want to use them with Serverless, you’ll likely get the most value out pairing with On-demand Builders.
- Relevant talk video (21 minutes): Eleventy: Build vs. Serverless vs. Edge