Open thedamon opened 1 year ago
Good suggestion! How about renderFileSafe
as the name of the shortcode?
const fs = require("node:fs");
const path = require("node:path");
const { EleventyRenderPlugin } = require("@11ty/eleventy");
/**
* @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
* @returns {ReturnType<import("@11ty/eleventy/src/defaultConfig")>}
*/
module.exports = function (eleventyConfig) {
eleventyConfig.addPlugin(EleventyRenderPlugin);
eleventyConfig.addAsyncShortcode("renderFileIfExists", async function (filename, data={}) {
filename = path.join("./src/_includes", filename);
if (fs.existsSync(filename)) {
return eleventyConfig.javascriptFunctions.renderFile(filename, data);
}
return "";
});
return {
dir: {
input: "src",
output: "www",
}
};
};
---
title: Cats
---
{%- set desc = "tags/" + page.fileSlug + ".md" -%}
{%- renderFileIfExists desc %}
Cat things here.
---
title: Dogs
---
{%- set desc = page.fileSlug + ".md" -%}
{% renderFileIfExists desc %}
Dog things here.
# CATS LIVE HERE
They _sometimes_ catch mice.
<h1>CATS LIVE HERE</h1>
<p>They <em>sometimes</em> catch mice.</p>
Cat things here.
Dog things here.
tree -A --gitignore
.
├── eleventy.config.js
├── package-lock.json
├── package.json
├── src
│ ├── _includes
│ │ └── tags
│ │ └── cats.md
│ ├── cats.njk
│ └── dogs.njk
└── www
├── cats
│ └── index.html
└── dogs
└── index.html
6 directories, 8 files
If you want a more .addFilter()
approach:
const fs = require("node:fs");
eleventyConfig.addFilter("fsExists", function (filename) {
return fs.existsSync(filename);
});
{%- set desc = "src/_includes/tags/" + page.fileSlug + ".md" -%}
{% if desc | fsExists %}
{% renderFile desc %}
{% endif %}
A bit more verbose, but possibly more flexible.
Yes! I think the filter approach gives more utility for other cases.
Though it’s hard to resist the first approach and calling the shortcode
renderFileGently
On Sat, Sep 16, 2023 at 19:43 Peter deHaan @.***> wrote:
If you want a more .addFilter() approach: eleventy.config.js (snippet)
const fs = require("node:fs");
eleventyConfig.addFilter("fsExists", function (filename) { return fs.existsSync(filename); });
src/cats.njk
{%- set desc = "src/_includes/tags/" + page.fileSlug + ".md" -%}{% if desc | fsExists %} {% renderFile desc %}{% endif %}
A bit more verbose, but possibly more flexible.
— Reply to this email directly, view it on GitHub https://github.com/11ty/eleventy/issues/3051#issuecomment-1722342440, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAKPYI4QKTRUR7AXZ2QZ6LLX2Y2TPANCNFSM6AAAAAA43BTVC4 . You are receiving this because you authored the thread.Message ID: @.***>
@thedamon You could do some hybrid solution that uses the shortcode but still lets you use the filter for other things (like checking for global data files or whatever):
eleventyConfig.addFilter("file_exists", function (filename, throwOnMissing=false) {
const exists = fs.existsSync(filename);
if (throwOnMissing && !exists) {
throw new Error(`Missing file: "${filename}"`);
}
return exists ? filename : false;
});
eleventyConfig.addAsyncShortcode("renderFileIgnoreMissing", async function (filename, data={}) {
const fileExists = eleventyConfig.getFilter("file_exists");
if (!!fileExists(filename)) {
return eleventyConfig.javascriptFunctions.renderFile(filename, data);
}
return "";
});
A:
{%- set descA = ("src/_includes/tags/" + page.fileSlug + ".md") | file_exists -%}
{%- renderFileIgnoreMissing descA %}
---
B:
{%- set descB = ("src/_includes/tags/" + page.fileSlug + ".md") | file_exists() -%}
{% if descB %}
{% renderFile descB %}
{% endif %}
---
C:
{%- set descC = ("src/_includes/tags/" + page.fileSlug + ".md") | file_exists(true) -%}
{% renderFile descC %}
Both example A and B should work since we're using our custom renderFileIgnoreMissing
shortcode or wrapping the native renderFile
in a conditional check.
Example C should fail loud since we're setting the throwOnMissing
argument which throws a build error.
UPDATE: Sorry, I re-read this and it's a bit of a mess. Probably worth explaining this filter:
eleventyConfig.addFilter("file_exists", function (filename, throwOnMissing=false) {
const exists = fs.existsSync(filename);
if (throwOnMissing && !exists) {
throw new Error(`Missing file: "${filename}"`);
}
return exists ? filename : false;
});
Basically the probably-confusingly-named file_exists
filter no longer returns a Boolean, but either the input filename or false
(or throws a hard error if throwOnMissing
is truthy).
Also confusing is that now the string concatenation needs to be wrapped in parens, or apparently the | file_exists
filter was only applying to that last segment (if I remember correctly -- so it was trying to do ".md" | file_exists
and then prefix that result with `"src/_includes/tags")).
Is your feature request related to a problem? Please describe.
I want to pull in files dynamically, associating markdown descriptions of taxonomies and other things like so:
In this scenario, though, if the tag does not exist eleventy will fail to build.
Describe the solution you'd like
It seems potentially useful to be able to opt not to fail if the file is not there today. Probably best would be an additional shortcode that has a try/catch in it:
{% renderFileIfExists desc %}
Nunjucks as an option in include:
{% include "missing.html" ignore missing %}
Describe alternatives you've considered
A simple way to check the existence of the file in another variable or maybe more helpfully overall adding a custom
{% try %}
block to supported templating languages then I could instead doAdditional context
No response