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

Add eleventy.beforeAll event #2427

Closed
paulshryock opened this issue Jun 10, 2022 · 4 comments
Closed

Add eleventy.beforeAll event #2427

paulshryock opened this issue Jun 10, 2022 · 4 comments
Labels
enhancement feature: 🛠 configuration Related to Eleventy’s Configuration file

Comments

@paulshryock
Copy link
Contributor

paulshryock commented Jun 10, 2022

Problem: When I add some code to an event like eleventy.before or eleventy.beforeWatch, this code runs before every build (or every re-build). But there is not an easy way to run some code only once before the very first build.

Solution: A new eleventy.beforeAll event that would run once before the first build (but would not run again before any rebuilds while watching or serving) would provide a great way to run some code once before the first build.

Alternatives: I could run some code in a separate script instead of putting it in the Eleventy config.

Context: An eleventy.beforeAll event would allow me to keep my code together in one place instead of splitting it apart across several files.

@zachleat
Copy link
Member

Just thinking out loud, if you have an .eleventy.js you can do this something similar without events:

console.log( "outside" );
module.exports = function(eleventyConfig) {
  console.log( "inside" );
};

Both of the above will only run at the beginning of a project. The exception being that if you save your .eleventy.js they will re-run again.

@zachleat zachleat added the feature: 🛠 configuration Related to Eleventy’s Configuration file label Jun 15, 2022
@paulshryock
Copy link
Contributor Author

@zachleat Thanks for the suggestion! That should definitely work for synchronous tasks.

I'm trying to update some files on the file system once before running Eleventy... Is it possible to run async tasks before Eleventy from ./eleventy.js?

Again I can always still run some code in a separate script instead of putting it in the Eleventy config, but just trying to see if there's a way to finagle this in lieu of an eleventy.beforeAll event, in order to keep everything contained in one place.

Here's what I've tried:

  1. Making .eleventy.js an ES Module so I can use top level await before declaring the export (this would be ideal) -- but Eleventy expects a Common JS config file and uses require()

    // package.json
    {
      "type": "module"
    }
    // .eleventy.js
    async function doSomething() {}
    await doSomething()
    export default function(eleventyConfig) {
        return {}
    }
    $ eleventy --quiet
    
    [11ty] Eleventy CLI Fatal Error: (more in DEBUG output)
    [11ty] 1. Error in your Eleventy config file '/path/to/project/.eleventy.js'. (via EleventyConfigError)
    [11ty] 2. require() of ES Module /path/to/project/.eleventy.js from /path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js not supported.
    [11ty] Instead change the require of .eleventy.js in /path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js to a dynamic import() which is available in all CommonJS modules. (via Error)
    [11ty]
    [11ty] Original error stack trace: Error [ERR_REQUIRE_ESM]: require() of ES Module /path/to/project/.eleventy.js from /path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js not supported.
    [11ty] Instead change the require of .eleventy.js in /path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js to a dynamic import() which is available in all CommonJS modules.
    [11ty]     at TemplateConfig.mergeConfig (/path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js:263:23)
    [11ty]     at TemplateConfig.getConfig (/path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js:138:26)
    [11ty]     at new Eleventy (/path/to/project/node_modules/@11ty/eleventy/src/Eleventy.js:75:39)
    [11ty]     at Object.<anonymous> (/path/to/project/node_modules/@11ty/eleventy/cmd.js:70:16)
  2. Exporting an async function so I can use await inside it -- but Eleventy doesn't want the export to return a Promise

    # .eleventy.js
    async function doSomething() {}
    module.exports = async function(eleventyConfig) {
        await doSomething();
        return {};
    }
    $ eleventy --quiet
    
    [11ty] Eleventy CLI Fatal Error: (more in DEBUG output)
    [11ty] 1. Error in your Eleventy config file '/path/to/project/.eleventy.js'. (via EleventyConfigError)
    [11ty] 2. Error in your Eleventy config file '/path/to/project/.eleventy.js': Returning a promise is not yet supported. (via EleventyConfigError)
    [11ty]
    [11ty] Original error stack trace: EleventyConfigError: Error in your Eleventy config file '/path/to/project/.eleventy.js': Returning a promise is not yet supported.
    [11ty]     at TemplateConfig.mergeConfig (/path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js:273:19)
    [11ty]     at TemplateConfig.getConfig (/path/to/project/node_modules/@11ty/eleventy/src/TemplateConfig.js:138:26)
    [11ty]     at new Eleventy (/path/to/project/node_modules/@11ty/eleventy/src/Eleventy.js:75:39)
    [11ty]     at Object.<anonymous> (/path/to/project/node_modules/@11ty/eleventy/cmd.js:70:16)
    [11ty]     at Module._compile (node:internal/modules/cjs/loader:1112:14)
    [11ty]     at Module._extensions..js (node:internal/modules/cjs/loader:1166:10)
    [11ty]     at Module.load (node:internal/modules/cjs/loader:988:32)
    [11ty]     at Module._load (node:internal/modules/cjs/loader:834:12)
    [11ty]     at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    [11ty]     at node:internal/main/run_main_module:17:47
  3. Running my async tasks in an IIFE async function before declaring the export -- but the IIFE itself is run syncronously

    async function doSomething() {}
    ;(async function() {
        await doSomething()
    })()
    module.exports = function(eleventyConfig) {
        return {};
    }
    
    // Eleventy runs successfully, but the async task is not completed before Eleventy starts.

@zachleat zachleat added this to the Post 2.0.0 Release milestone Jan 6, 2023
@zachleat zachleat removed this from the Eleventy 2.0.1 milestone Mar 17, 2023
@zachleat zachleat added this to the Eleventy 3.0.0 milestone Apr 8, 2024
@zachleat
Copy link
Member

zachleat commented Apr 8, 2024

I believe the original suggestion will work better now with the advent of async configs in v3.0. See #614.

Let me know if this doesn’t work for this use case somehow!

@zachleat zachleat closed this as completed Apr 8, 2024
@paulshryock
Copy link
Contributor Author

This works great in v3.x!

package.json:

{
  "type": "module",
  "scripts": {
    "compile": "eleventy",
    "watch": "npm run compile -- --watch",
    "serve": "npm run compile -- --serve"
  },
  "devDependencies": {
    "@11ty/eleventy": "3.0.0-alpha.5"
  }
}

eleventy.config.js:

import { writeFile } from 'node:fs/promises'

const content = `# The title

Lorem ipsum dolor sit amet.
`

await writeFile('src/index.md', content, 'utf8')

export default async function(eleventyConfig) {
  return {
    dir: {
      input: 'src',
      output: 'dist',
    },
  }
}

This results in src/index.md being recreated once whether I run compile, watch, or serve. Subsequent runs while watching or serving do not recreate the file, as writeFile is only run once.

That's exactly what I was looking for.

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
Projects
None yet
Development

No branches or pull requests

2 participants