Skip to content
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

Enable plugins to be async #2675

Closed
robole opened this issue Dec 4, 2022 · 10 comments
Closed

Enable plugins to be async #2675

robole opened this issue Dec 4, 2022 · 10 comments
Labels
enhancement feature: 🛠 configuration Related to Eleventy’s Configuration file feature: esm Related to supporting ES Modules (in parallel to CommonJS)

Comments

@robole
Copy link

robole commented Dec 4, 2022

Is your feature request related to a problem? Please describe.
There is a 11ty plugin for the syntax highlighting library shiki twoslash. This libary uses WASM under the hood and needs to run asynchronously. In the plugin, they need to fudge synchronous behavior by using the deasync to make it run in 11ty. For this reason, the performance is poor.

For example, at the moment, I am currently migrating a website to 11ty with 100 pages and the build time is 1.5seconds, with incremental builds a file change reloads in milliseconds. If I add the twoslash plugin, it pushes the build time to 8 seconds, and incremental builds take the same time. Having that as a dev mode experience is too painful.

Describe the solution you'd like
Permitting an async function to be used by addPlugin().

Describe alternatives you've considered
Using deasync is the alternative tried.

@pdehaan
Copy link
Contributor

pdehaan commented Dec 4, 2022

I haven't tried twoslash, but aren't async plugins already supported?
Or is this more of an issue w/ overriding the highlighting?

// .eleventy.js
/**
 * @param {import("@11ty/eleventy/src/UserConfig")} eleventyConfig
 * @returns {ReturnType<import("@11ty/eleventy/src/defaultConfig")>}
 */
module.exports = function (eleventyConfig) {
  eleventyConfig.addPlugin(require("./plugins/test"));

  return {
    dir: {
      input: "src",
      output: "www",
    }
  };
};
// plugins/test.js
module.exports = async (eleventyConfig, opts={}) => {
  eleventyConfig.addFilter("test_filter", (val) => val.toString().toUpperCase());
};
---
# src/index.liquid
title: inDex
---

<p>{{ title | test_filter }}</p>

OUTPUT

<p>INDEX</p>

@robole
Copy link
Author

robole commented Dec 4, 2022

As far as I can tell, you can have async filters in v2.0 (see docs) and async shortcodes (see docs), but everything else has to be synchronous in the config (.eleventy.js). In this case, a filter or shortcode is not what is needed. You need to be able to use await .

It is this type of behaviour that would be desirable:

// .eleventy.js
const shikiTwoslash = require("eleventy-plugin-shiki-twoslash")

module.exports = function (eleventyConfig) {
  eleventyConfig.addPlugin(shikiTwoslash, { theme: "nord" })
}
//index.js of "eleventy-plugin-shiki-twoslash" plugin
const { setupForFile, transformAttributesToHTML } = require("remark-shiki-twoslash")

module.exports = async function (eleventyConfig, options = {}) {
  /** @type {import("shiki").Highlighter[]} */
  let highlighters = await setupForFile(options);

  eleventyConfig.addMarkdownHighlighter((code, lang, fence) => {
    code = code.replace(/\r?\n$/, "") // strip trailing newline fed during code block parsing
    return transformAttributesToHTML(code, [lang, fence].join(" "), highlighters, options)
  })
}

There is an open issue - Allow configuration to return a promise (async-friendly) - related to this too.

@zachleat zachleat added this to the Eleventy 3.0.0 milestone Dec 5, 2022
@zachleat
Copy link
Member

zachleat commented Dec 5, 2022

This will come with ESM, which unlocks top-level async/await in Node.js. Look for a build of this early next year, shortly after 2.0 stable ships

@zachleat
Copy link
Member

zachleat commented Dec 5, 2022

In the mean time, here is how I’ve worked around it in projects on 2.0, there are a few async-friendly hooks you can tie into for now:

  1. https://www.11ty.dev/docs/events/#eleventy.before
  2. https://www.11ty.dev/docs/languages/custom/#init (for custom template syntaxes)

@zachleat zachleat added the feature: 🛠 configuration Related to Eleventy’s Configuration file label Dec 5, 2022
@zachleat zachleat added the feature: esm Related to supporting ES Modules (in parallel to CommonJS) label Aug 28, 2023
@zachleat
Copy link
Member

Related to #614

@zachleat
Copy link
Member

Almost there in PR #3074, we just need to support async in addPlugin too.

@zachleat
Copy link
Member

zachleat commented Oct 24, 2023

Code is complete to support this (in PR #3074):

await eleventyConfig.addPlugin(async () => {
  // do async stuff
});

(and as documented in #614, module.exports = async function(eleventyConfig) too)

@devurandom
Copy link

devurandom commented Nov 10, 2023

Is there a workaround for Eleventy 2.0.1 for plugins that come as ESM modules and addTemplateFormats and addExtension?

@zachleat
Copy link
Member

@devurandom that seems unrelated to me, can you file a new issue?

@zachleat zachleat added the needs-documentation Documentation for this issue/feature is pending! label May 30, 2024
zachleat added a commit to 11ty/11ty-website that referenced this issue Sep 26, 2024
@zachleat
Copy link
Member

Temporary docs preview building here: https://11ty-website-git-v3-11ty.vercel.app/docs/plugins/

@zachleat zachleat removed the needs-documentation Documentation for this issue/feature is pending! label Sep 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement feature: 🛠 configuration Related to Eleventy’s Configuration file feature: esm Related to supporting ES Modules (in parallel to CommonJS)
Projects
None yet
Development

No branches or pull requests

4 participants