vercel / ncc

Compile a Node.js project into a single file. Supports TypeScript, binary addons, dynamic requires.
https://npmjs.com/@vercel/ncc
MIT License
8.99k stars 285 forks source link

ESM mode still uses "require" within an ESM module #1163

Open onigoetz opened 4 months ago

onigoetz commented 4 months ago

Hi,

I'm trying to bundle my dependencies within an ESM package I get mixed results depending if the module I compile is using ESM or CJS.

Here is an example of three packages I'm trying to bundle, each in their separate file;

When compiling these three modules they all compile fine, and create a package.json containing { "type": "module" }.

However, within string-width, NCC (I guess because of the asset relocator) require calls are transformed to the following:

/***/ 695:
/***/ ((module) => {

module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("../is-fullwidth-code-point/index.mjs");

/***/ }),

Which fails when we try to run it since the result is a require of an ESM module:

Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/is-fullwidth-code-point/index.mjs not supported.
Instead change the require of /Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/is-fullwidth-code-point/index.mjs to a dynamic import() which is available in all CommonJS modules.
    at 695 (file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:74:67)
    at __nccwpck_require__ (file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:107:41)
    at 871 (file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:22:30)
    at __nccwpck_require__ (file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:107:41)
    at file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:146:70
    at file:///Users/onigoetz/Sites/Libs/crafty/packages/crafty-preset-stylelint/dist/string-width/index.mjs:148:3

is there a way to tell the asset relocator that the destination is an ESM module and it should let webpack hoist the dependency ?

mr-short commented 4 months ago

I am also running into this issue. Running with sourcemaps also gives ReferenceError: __dirname is not defined in ES module scope. It seems it is still using the global __dirname which you cannot in ESM.

styfle commented 4 months ago

This sounds like a duplicate of https://github.com/vercel/ncc/issues/749

onigoetz commented 4 months ago

It is not, #749 mentions wanting to output CJS within an ESM module, and it can't access dirname / filename

This is issue is about outputing ESM in an ESM module, and importing other ESM modules. But NCC's transformations tries to require an ESM module

styfle commented 4 months ago

Oops, I meant duplicate of #791

onigoetz commented 4 months ago

It is similar to #791 but not really

All cases in #791 point on a missing createRequire (which BTW seems to work fine now)

My case is that I have require / createRequire but wish to have import (because what I'm importing is an ESM module)

Chocrates commented 4 months ago

I think I have the same error. I upgraded a package that required me to update my script to be a module so I could use import. Now I can run the script manually just fine, but once I compile it with ncc and try to run it, it fails

file:///home/chris/workspace/chocrates/actions-governance/dist/exec-child.js:1
if (require.main !== module) {
^

ReferenceError: require is not defined in ES module scope, you can use import instead
This file is being treated as an ES module because it has a '.js' file extension and '/home/chris/workspace/chocrates/actions-governance/dist/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///home/chris/workspace/chocrates/actions-governance/dist/exec-child.js:1:1
    at ModuleJob.run (node:internal/modules/esm/module_job:192:25)
    at async DefaultModuleLoader.import (node:internal/modules/esm/loader:228:24)
    at async loadESM (node:internal/process/esm_loader:40:7)
    at async handleMainPromise (node:internal/modules/run_main:66:12)

There are no require's in my codebase anymore and it looks like the generated exec-child.js is the culprit.