11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
17.1k stars 494 forks source link

Allow object passed to `setLibrary` to alter permalinks #3021

Closed audiodude closed 1 year ago

audiodude commented 1 year ago

Is your feature request related to a problem? Please describe.

I'm using the following code in an alternate .eleventy.gemini.js config file to create a Gemini version of my site:

  eleventyConfig.setLibrary('md', {
    render: async (data) => {
      const gemdown = await import('gemdown');
      return gemdown.md2gemini(data);
    }
  });

Where gemdown is a ESM module from a package I also wrote (https://github.com/audiodude/gemdown) for this purpose.

The current problem I'm facing is that eleventy creates files with .html extensions.

Describe the solution you'd like

I would like to be able to specify a permalink key to the object passed to setLibrary, in order to alter the permalinks and create files with the extension .gmi.

So:

  eleventyConfig.setLibrary('md', {
    permalink: (_, inputPath) => {
      return inputPath.substr(0, inputPath.lastIndexOf('.')) + '.gmi';
    },
    render: async (data) => {
      const gemdown = await import('gemdown');
      return gemdown.md2gemini(data);
    }
  });

Describe alternatives you've considered

Post processing the output tree with command line tools to replace .html with .gmi.

Additional context

I believe that it would be possible to keep the interface for permalinks documented here and just expose it to the addLibrary method.

pdehaan commented 1 year ago

I was wondering if https://www.11ty.dev/docs/languages/custom/ would potentially work. I haven't tried .gmi files, but wondering if you could set the extension to the input files as .gmi and then also control the output file extension. Although it does have this big ominous INFO warning:

"If you want to pre-process md or html files using another template language, change the Default Template Engine for Markdown Files or HTML Files, respectively. This can also be done on a per-template basis. We will likely add additional hooks for preprocessing in the future."

pdehaan commented 1 year ago

Another workaround might be using eleventyComputed to try rewriting .md files to .gmi using a directory data file:

module.exports = {
  eleventyComputed: {
    permalink(data) {
      if (data.permalink) {
        return data.permalink;
      }
      const p = data.page;
      if (p.inputPath.endsWith(".md")) {
        const stem = p.filePathStem;
        return stem.endsWith("/index") ? `${stem}.gmi` : `${stem}/index.gmi`;
      }
    }
  }
};
eleventy

[11ty] Writing www/pages/index.gmi from ./src/pages/index.md (liquid)
[11ty] Writing www/pages/one/index.gmi from ./src/pages/one.md (liquid)
[11ty] Writing www/pages/three/index.html from ./src/pages/three.njk
[11ty] Writing www/pages/two/index.gmi from ./src/pages/two.md (liquid)
[11ty] Wrote 4 files in 0.06 seconds (v2.0.1)
audiodude commented 1 year ago

Another workaround might be using eleventyComputed to try rewriting .md files to .gmi using a directory data file:

Is there a way I could integrate that with my .eleventy.gemini.js file? I don't want it to happen for the HTML version of the site.

pdehaan commented 1 year ago

Possibly via .addGlobalData() in your config and see if eleventyComputed doesn't conflict there. You might be in uncharted territory (at least for me, maybe others have ventured down this path):

/**
 * @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
 * @returns {ReturnType<import("@11ty/eleventy/src/defaultConfig")>}
 */
module.exports = function (eleventyConfig) {
  eleventyConfig.addGlobalData("eleventyComputed", () => {
    return {
      permalink(data) {
        if (data.permalink) {
          return data.permalink;
        }
        const { inputPath, filePathStem } = data.page;
        if (inputPath.endsWith(".md")) {
          let suffix = ".gmi";
          if (!filePathStem.endsWith("/index")) {
            suffix = "/index" + suffix;
          }
          return `${filePathStem}${suffix}`;
        }
      },
    };
  });

  return {
    dir: {
      input: "src",
      output: "www",
    }
  };
};
pdehaan commented 1 year ago

Not sure if another approach might be wrapping some logic with an ENV var, or checking your NODE_ENV. So if you're in development mode, it saves as .gmi files, but if you're in production mode it saves as .html files.

audiodude commented 1 year ago

Using addGlobalData worked! Thanks so much for looking into this so thoroughly, greatly appreciated!

davidvasandani commented 11 months ago

Another workaround might be using eleventyComputed to try rewriting .md files to .gmi using a directory data file:

module.exports = {
  eleventyComputed: {
    permalink(data) {
      if (data.permalink) {
        return data.permalink;
      }
      const p = data.page;
      if (p.inputPath.endsWith(".md")) {
        const stem = p.filePathStem;
        return stem.endsWith("/index") ? `${stem}.gmi` : `${stem}/index.gmi`;
      }
    }
  }
};
eleventy

[11ty] Writing www/pages/index.gmi from ./src/pages/index.md (liquid)
[11ty] Writing www/pages/one/index.gmi from ./src/pages/one.md (liquid)
[11ty] Writing www/pages/three/index.html from ./src/pages/three.njk
[11ty] Writing www/pages/two/index.gmi from ./src/pages/two.md (liquid)
[11ty] Wrote 4 files in 0.06 seconds (v2.0.1)

I ran into issues where because data.permalink already existed, and if (inputPath.endsWith(".md")) was never executed. Replacing it with the following helped with my setup (and hopefully helps others).

eleventyConfig.addGlobalData('eleventyComputed', {
  permalink: data => {
    if (data.permalink && data.permalink.endsWith('.html')) {
      return data.permalink.replace('.html', '.gmi');
    }
    return data.permalink;
  },
});