3

I'm trying to create yeoman generator but I'm unable to get started. I'm following this video on the subject and I can't even get my code to run.

here's my package.json file:

{
  "name": "generator-test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "yeoman-generator": "^7.1.0"
  }
}

and my index.js file:

const Generator = require("yeoman-generator");

module.exports = class extends Generator {
  initializing() {
    this.log("working!");
  }
};

I can run npm link no issues, and when I try to run it I can see it's been hit, but then I get this error:

require() of ES Module ...\generator-test\node_modules\yeoman-generator\dist\index.js from ...\generator-test\generators\app\index.js not supported.

Instead change the require of ...\generator-test\node_modules\yeoman-generator\dist\index.js in ...\generator-test\generators\app\index.js to a dynamic import() which is available in all CommonJS modules.

so I tried that, and ended up with this index.js:

import Generator from "yeoman-generator";

module.exports = class extends Generator {
  initializing() {
    this.log("working!");
  }
};

and this error:

Cannot use import statement outside a module

I'm sure I'm doing something wrong I just don't what it is. Can some one point me in the right direction?

3
  • 1
    It says dynamic import not static. You can also change your project to ESM since your version of yeoman is using ESM Commented Nov 3, 2023 at 14:14
  • 1
    I'm not following you, I'm not experienced enough in JS. I actually just got it working but setting "type": "module" on my package.json and using import instead of require. But it feels "hacky" to me. Can you elaborate on your suggestion? Commented Nov 3, 2023 at 14:27
  • Glad you got it working. There is nothing hacky about using ESM in your project, it is the current standard (one of them anyways). It actually would be more "hacky" imo to chose an ESM dependency and then consume it from your CJS project via a dynamic import(). Commented Nov 3, 2023 at 14:34

1 Answer 1

8
+150

UPDATE

Node.js >= v22.0.0 now has experimental support for loading ES modules with require. See Loading ECMAScript modules using require().

In summary:

  • use --experimental-require-module.
  • The ES module must be fully synchronous, i.e no top-level await.
  • One of the usual methods for determining an ES module is in place:
    • .mjs extension.
    • "type": "module" in package.json.
    • --experimental-detect-module is enabled.

Original Answer

First, your selected version of yeoman is published as an ES module which means it can not be consumed with require.

Second, your project is defined as CJS because your package.json is not defining "type": "module", so defaults to common JS.

If you want to continue using CJS in your project, then to consume yeoman you need to use a dynamic import() expression which is available in both ESM and CJS contexts. Going this route you should probably use top level await to define your index.js module since dynamic imports use promises. Something along these lines:

const setup = async () => {
  const Generator = await import('yeoman-generator')

  return class extends Generator {
    initializing() {
      this.log("working!");
    }
  }
}

export default await setup()

The far simpler option is to use ESM in your project by setting "type": "module" in your package.json file and changing your require calls to import.

import Generator from "yeoman-generator";

export default class extends Generator {
  initializing() {
    this.log("working!")
  }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.