-
-
Notifications
You must be signed in to change notification settings - Fork 495
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Configuration API method to create a content template (aka Virtual Templates) #1612
Comments
|
I had a quick stab at implementing this to see what's involved and how deep the rabbit hole could go. I got this far: keithclark#1. The approach seems to work, albeit with very limited testing. If I'm on the right track then I'll explore further. |
@zachleat is there anything I can do to help develop this feature request or does it need more votes first? |
If I had more than one vote, I would use them all here. I need this to finally transition away from my "sparse collection" hacks. |
Shipping with 3.0.0-alpha.6 Tests here: https://github.com/11ty/eleventy/blob/main/test/EleventyVirtualTemplatesTest.js Examples: eleventyConfig.addTemplate("inputPath.md", "# Template Content"); // Parses front matter
eleventyConfig.addTemplate("inputPath.md", `---
myKey: myValue
---
# Template Content`); // Supplemental data (overrides front matter if conflicts)
eleventyConfig.addTemplate("inputPath.md", "# Template Content", { myKey: "myValue" }); If you create a virtual template with the same path as a file system template, we throw an error. Virtual templates and file system templates that attempt to write to the same output location will throw a duplicate permalink error as expected. Otherwise I would expect virtual templates and file system templates to operate the same, in practice. Update April 8: this was changed so that paths passed to |
Thanks for adding this. |
@zachleat your example here and all tests are using Does it work for any template type? Also, if the purpose is to allow "automatic content creation in plugins", would it make sense to allow the second parameter to be a path to a template file provided by the plugin, path that could be relative to the plugin root? Or maybe it requires an additional function: eleventyConfig.addTemplateFile("./src/inputPath.md", "./src/template-in-plugin.njk", { myKey: "myValue" }); |
If the file is virtual why does it need an input path and not just an output path/permalink? Is it just a workaround for the rest of eleventy expecting files to have an input path? |
I understand it as an output path, to the sources that will be then computed by Eleventy. |
I know it's too early and that docs will come later for this, but noting my question here so I don't forget: Let's say I'm authoring a plugin that uses this new API. Do I need to ask users for their preferred template language, or can I safely use any template language in the plugin, even one that the user's Eleventy config does not support? e.g., if a user authors all of their templates in Nunjucks but I want to write my plugin's template content in Liquid, can I do that or does my plugin need to accept the template language and |
Yes! That’s the goal! Though saying this out loud I think
I think it might be more ergonomic to make these paths default to relative to the project’s input directory (rather than project root) with maybe an escape hatch via
I think that’s a fair question! Input paths in Eleventy are the default mechanism (they imply both the template syntax and the default output path) for the MVP of this feature but I think we could add additional functionality:
|
This will have the same limitations of a file system template. So if I add a virtual template that uses That said, there are configuration API methods to add valid template formats programmatically (e.g. |
So for a plugin, it would be |
@nhoizey No, that usage seems unlikely to me. The plugin would populate virtual templates in the input directory, so from a plugin usage might be like this: I’d imagine plugins would offer an override inputPath as part of the options you pass in, for further control. |
I'm not sure I understand, I'll have to test it! 😅 |
Just a bonus thought here, I think Virtual Templates could replace some advanced Pagination use cases, where the declarative configuration in front matter is just too weak (or too confusing). Pagination does buy you shared resources between pages and might be faster, but that is a claim that would require testing! https://www.11ty.dev/docs/pagination/ export default function(eleventyConfig) {
let pages = [1, 2, 3];
for(let index of pages) {
eleventyConfig.addTemplate(`pagination-${index}.njk`, `Page {{ pageNumber }}`, {
pageNumber: index,
permalink: `/page-${index}/`
});
}
}; |
A |
@zachleat /others: If you were a user of such a plugin, what would your expected API be? I can think of two options:
(Either way, it would also offer an option to fetch a list of AI crawlers and dump that into the I'm leaning towards the second option at the moment, but I'm not sure. Example usage here: https://github.com/AleksandrHovhannisyan/eleventy-plugin-robotstxt/blob/73b3fd3c67c8505bae498987d13565571399bdd3/example/.eleventy.js#L4-L13 It does make me wonder though what the advantage would be to doing this: eleventyConfig.addPlugin(thePlugin, {
rules: new Map(
['*', [{ disallow: '/404' }]],
[['agent1', 'agent2'], [{ disallow: '/1', allow: '/1/2/' }]],
);
}); Instead of just creating that |
This post and this thread seem to indicate that these new virtual templates could help solve the double layered pagination use case somewhat elegantly. Lets say I have a collection containing unique categories and posts as arrays of objects for each categories. How should I approach paginated category pages ? Conceptually, I suppose I should be able to:
Now how to implement it ... |
@jeromecoupe In the virtual template, you would just write the same content as you would in any ordinary template. So for example, you can reference In your case of double pagination (which I implemented on my blog using your article, by the way!), you could create a virtual tag/tags template. The challenge here is giving users of the plugin control over how the content is rendered or what permalink format to use. You might need to give your plugin render props/functions for these bits of info. As an example of how you might implement this, see this code (experimental plugin I wrote that uses this feature): |
@AleksandrHovhannisyan Yep I had a look at your plugin for inspiration (let's call it inspiration cross-pollination). My main blocker right now is that I need to create a custom 11ty collection and, within that, create a virtual template for each item in that collection. I didn't find a way (yet) to use export default function (eleventyConfig) {
eleventyConfig.addCollection("blogpostsByCategories", function (collectionApi) {
const blogposts = collectionApi.getFilteredByGlob(
"./src/content/blogposts/*.md"
);
// [ ... more code ... ]
// find a way to use addTemplate here or to pass this collection I just defined to an external function
}
} |
@jeromecoupe Hmm, I think I understand the problem now. If your goal is to do something like @zachleat Just brainstorming here, what if Also wondering if we should open up a GitHub Discussion for virtual templates as it seems like we all have various pending questions about this. |
I also need the ability to add virtual templates to collections. |
Virtual pagination template that paginates over various collections should work! |
Wrote a short blog post about this: https://www.aleksandrhovhannisyan.com/blog/eleventy-virtual-templates/ |
v3.0.0-alpha.15 will ship with the ability to add Eleventy Layout files as Virtual Templates. (for #2307) Just map the template virtual path to be inside the Usage example: export default function(eleventyConfig) {
eleventyConfig.addTemplate("virtual.md", `# Hello`, {
layout: "virtual.html"
});
eleventyConfig.addTemplate("_includes/virtual.html", `<!-- Layout -->{{ content }}`);
}; These virtual layouts should have the same functionality as an Eleventy layout on the file system. |
For plugins, they may want to use the following pattern (if you don’t know what a project’s export default function(eleventyConfig) {
eleventyConfig.addTemplate("virtual.md", `# Hello`, {
layout: "virtual.html"
});
let layoutPath = eleventyConfig.directories.getLayoutPathRelativeToInputDirectory("virtual.html");
eleventyConfig.addTemplate(layoutPath, `<!-- Layout -->{{ content }}`);
}; |
I'm using several JS classes as templates in a few projects. How would I add those as virtual templates? Do I have to add import MyTemplate from '#templates/test';
export default new MyTemplate(); as the content string in (This didn't work the first time I tried it but it could have very well been my fault. Unfortunately, I haven't had the time yet to investigate further.) |
@VividVisions follow along to #3347 please! |
Temporary docs preview building now: Changed my mind it lives here now https://11ty-website-git-v3-11ty.vercel.app/docs/virtual-templates/ |
Would need:
This would allow automatic content creation in plugins (sitemap.xml, rss feeds, etc)
The text was updated successfully, but these errors were encountered: