noelforte


Expose Universal Filters and Shortcodes in configuration API (to load into custom engines that support them)

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

It would be nice to have access to a list of Universal Filters and Shortcodes in the configuration API. I just released eleventy-plugin-vento v1 to add support for the Vento templating language by @oscarotero. Vento has the ability to use custom filters and tags, but retrieving these things from Eleventy via a plugin feels a bit brittle.

Currently my implementation is approximately as follows (shortened for brevity):

// Create empty sets to hold user defined functions
const filters = {};
const helperFunctions = {};

for (const fn in eleventyConfig.javascriptFunctions) {
  if (
    eleventyConfig.liquidFilters[fn] &&
    (eleventyConfig.nunjucksFilters[fn] || eleventyConfig.nunjucksAsyncFilters[fn])
  ) {
    filters[fn] = javascriptFunctions[fn];
  } else {
    helperFunctions[fn] = javascriptFunctions[fn];
  }
}

and then farther down...

eleventyConfig.addExtension('vto', {
  async compile(inputContent, inputPath) {
    return async (data) => {
      // Rebind functions to page data so this.page,
      // this.eleventy, etc works as intended
      for (const helper in helperFunctions) {
        helperFunctions[helper] = helperFunctions[helper].bind(data);
      }

      // Rebind filters the same way
      for (const filter in filters) {
        VentoLib.filters[filter] = filters[filter].bind(data);
      }

      // Merge helpers into page data
      data = { ...data, ...helperFunctions };
    };
  },
});

Note that this does not include shortcodes, as the helperFunctions object seems to do the trick to handle single shortcodes.

Describe the solution you'd like

It would be great to be able to retrieve all filters at once via an eleventyConfig.universalFilters call to make loading in easily.

As for single and paired shortcodes, it would be great to have similiar properties (eleventyConfig.universalShortcodes/eleventyConfig.universalPairedShortcodes) to achieve a similar result.

It would also be nice to have some sort of mechanism for adding page context data to filters/shortcodes in custom templating languages, although I'm not quite sure what that would look like beyond the .bind(data) technique I used above since the bundled engines Eleventy ships with seem to rely on some internal methods to manage adding context to filters and shortcodes. I'm also curious if Eleventy does any sort of caching work when exposing this.page and this.eleventy contexts when running shortcodes and filters for bundled engines and if plugins could take advantage of that pipeline in some way.

Describe alternatives you've considered

As far as I know, there aren't any documented mechanisms to retrieve Universal Shortcodes/Filters. While there's plenty of ways to get data into the data cascade for custom templating languages (getData(), getInstanceFromPath()), retrieving data from the data cascade for custom templating languages outside of Eleventy's internal methods looks to be a bit harder to do.

My current approach gets close enough; merging javascriptFunctions() into the data cascade and binding page data to this since Vento can run JS directly. However, this doesn't handle paired shortcodes/custom tags, which is a feature I'd like to eventually have in Vento templates within Eleventy. This would require more filtering of eleventyConfig.javascriptFunctions in order to extract the shortcodes and manually set up the integrations with Eleventy and Vento, which might be out-of-scope for what a plugin can do.

Additional context

With the deprecation of HAML, Handlebars, EJS, and Pug in core for v3 and some of them moving to plugin-land, I realize that I might be ahead of the curve here.

I'd be curious to know if there's a preferred way to integrate a filter-and-custom-tag-capable language with Eleventy's core functionality inside of a plugin. If not, will there be plans to do so to accommodate some of the templating languages being moved into plugins for v3?