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

Version 6 is ESM only #489

Closed
soundstep opened this issue Feb 2, 2022 · 12 comments
Closed

Version 6 is ESM only #489

soundstep opened this issue Feb 2, 2022 · 12 comments

Comments

@soundstep
Copy link

soundstep commented Feb 2, 2022

I guess there is no way to use execa >= 6 in nodejs CommonJS projects?
I'm in a project where I can't add "type: module" in my package.json, that would be too big of a change.

This is a drastic change, why not export for both? Especially with all the drawbacks NodeJS ESM can have (file system, __dirname, path resolving, etc).

The error I got:

internal/modules/cjs/loader.js:1102
      throw new ERR_REQUIRE_ESM(filename, parentPath, packageJsonPath);
      ^

Error [ERR_REQUIRE_ESM]: Must use import to load ES Module:app/node_modules/.pnpm/execa@6.0.0/node_modules/execa/index.js
require() of ES modules is not supported.
require() of app/node_modules/.pnpm/execa@6.0.0/node_modules/execa/index.js from app/scripts/check-version.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from app/node_modules/.pnpm/execa@6.0.0/node_modules/execa/package.json.
@sindresorhus
Copy link
Owner

You can use await import() to import it from CommonJS: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

@soundstep
Copy link
Author

soundstep commented Feb 2, 2022

Amazing, working, thanks for the doc!

For others, in a NodeJS (14.x) CommonJS script:

(async () => {
        const execaCommand = (await import('execa')).execaCommand;
})();

@rattrayalex
Copy link

rattrayalex commented Apr 26, 2022

To save others who find this a bit of time, using TypeScript with CommonJS, the following code still threw an ESM error for me:

export default async function main() {
  const { execa } = await import('execa');

Instead, I added "execa": "^5.1.1", to my package.json and imported a named import:

import execa from 'execa';

I look forward to TS having better ESM support built in.

@michaelgwelch
Copy link

Amazing, working, thanks for the doc!

For others, in a NodeJS (14.x) CommonJS script:

(async () => {
        const execaCommand = (await import('execa')).execaCommand;
})();

I don't understand. You mean do this and then put your whole app inside of the closure? after the import of execa?

@ehmicky
Copy link
Collaborator

ehmicky commented May 10, 2022

Instead of using a closure, you can use a top-level await providing you use Node.js >=14.14.0:

const { execaCommand } = await import('execa')

Note: this is not specific to Execa, this applies to any pure ESM package.

@michaelgwelch
Copy link

Sure thanks @ehmicky, I'm one of those trying to figure out how to consume in a CommonJS script. I have no experience with ESM at all. I'll be researching how to convert in the near future, I guess.

@seanmorrisonit
Copy link

Just been wrangling this one as well. Here's where we go to but am getting the error A dynamic import callback was not specified.

So for now we will stick with 5.1.1.

Source for this code: https://stackoverflow.com/questions/70545129/compile-a-package-that-depends-on-esm-only-library-into-a-commonjs-package

    let execa: typeof t_execa | undefined
    if (typeof execa == 'undefined') {
        const mod = await (eval(`import('execa')`) as Promise<
            typeof import('execa')
        >)
        ;({ execa } = mod)
    }

@ghost
Copy link

ghost commented Aug 27, 2022

Does anyone know an alternative to this package that is not ESM only and that does support the AbortController?

@ghost
Copy link

ghost commented Aug 27, 2022

Nevermind, thanks - I found the fork with the CJS version, published at https://www.npmjs.com/package/@esm2cjs/execa

@rashil-gopee
Copy link

rashil-gopee commented Jan 16, 2024

This worked for me

import execa = require('execa')

@abejfehr
Copy link

abejfehr commented Feb 6, 2024

I'm not able to use a top level await in node 20, I'm told that:

SyntaxError: await is only valid in async functions and the top level bodies of modules

@ehmicky
Copy link
Collaborator

ehmicky commented Feb 6, 2024

Hi @abejfehr,

Top-level await is only available with ES modules. Please see the following instructions.

Please note this is not specific to Execa, i.e. might be more relevant for https://github.com/nodejs/node/issues.

facebook-github-bot pushed a commit to facebook/sapling that referenced this issue Nov 1, 2024
Summary:
In order to show progress all the way from EdenFS into ISL we need some a   communication channel between Sapling and ISL. NodeIPC is a great candidate for this, and newer versions of the execa package support this.

Unfortunately, upgrading to newer versions of execa is really difficult since:
- They introduce a few minor breaking changes to its API (e.g., timeouts for killing commands)
- Newer versions of execa are [ESM only](sindresorhus/execa#489), and making Jest work with this is really annoying.
- The [CJS fork of Execa](https://www.npmjs.com/package/esm2cjs/execa) hasn't been updated in a while and doesn't have the IPC capabilities we want

We still want the important bits of execa, however. Changing execa for direct calls to the native `child_process.spawn` is not something we want to do because that would be tricky and we would have to be really careful when mocking commands through Jest.

Because all of that, we've decided on creating a minimal clone of execa which only has the capabilities we already use in our codebase. This diff adds the skeleton for a new library called "ejeca" which does precisely that.

Reviewed By: evangrayk

Differential Revision: D65138584

fbshipit-source-id: 6591a31f8d5163e3285a5b1ef3e9e375faafd056
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants