vercel / ncc

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

"require is not defined in ES module scope" and mixed require/import using ESM with native modules #791

Open dmfay opened 2 years ago

dmfay commented 2 years ago

I'm trying to compile an ES module ("type": "module") that uses tree-sitter. The compiled distributable winds up importing createRequire as expected, but still tries to load native code via old-fashioned require.

package.json ```json { "name": "ncctest", "version": "1.0.0", "description": "", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "tree-sitter": "^0.19.0", "tree-sitter-javascript": "^0.19.0" }, "devDependencies": { "@vercel/ncc": "^0.31.1" } } ```
index.js ```js 'use strict'; import * as TreeSitter from 'tree-sitter'; import JavaScript from 'tree-sitter-javascript'; const parser = TreeSitter.default(); parser.setLanguage(JavaScript); ```
> npx ncc build index.js
> node dist/index.js
file:///home/dian/work/ncctest/dist/index.js:802
module.exports = require(__nccwpck_require__.ab + "build/Release/tree_sitter_runtime_binding.node")
^

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/dian/work/ncctest/dist/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at Object.460 (file:///home/dian/work/ncctest/dist/index.js:802:1)
    at __nccwpck_require__ (file:///home/dian/work/ncctest/dist/index.js:860:41)
    at Object.525 (file:///home/dian/work/ncctest/dist/index.js:35:13)
    at __nccwpck_require__ (file:///home/dian/work/ncctest/dist/index.js:860:41)
    at file:///home/dian/work/ncctest/dist/index.js:880:69
    at file:///home/dian/work/ncctest/dist/index.js:891:3
    at ModuleJob.run (node:internal/modules/esm/module_job:183:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
    at async handleMainPromise (node:internal/modules/run_main:63:12)

The offending require in question:

/***/ 460:
/***/ ((module, __unused_webpack_exports, __nccwpck_require__) => {

module.exports = require(__nccwpck_require__.ab + "build/Release/tree_sitter_runtime_binding.node")

/***/ }),
unicornware commented 2 years ago

having the same issue when trying to bundle a .mjs file (e.g: esm/index.mjs):

ReferenceError: require is not defined in ES module scope, you can use import instead
    at eval (eval at 874 (file:///Users/lex/Projects/FLDV/FLDV-P008/node_modules/@flex-development/trext/src/index.ts:7:15), <anonymous>:1:1)
    at Object.874 (file:///Users/lex/Projects/FLDV/FLDV-P008/node_modules/@flex-development/trext/src/index.ts:7:15)
    at __nccwpck_require__ (file:///Users/lex/Projects/FLDV/FLDV-P008/node_modules/@flex-development/trext/esm/trext.mjs:57:41)
    at file:///Users/lex/Projects/FLDV/FLDV-P008/node_modules/@flex-development/trext/esm/trext.mjs:100:81
    at file:///Users/lex/Projects/FLDV/FLDV-P008/node_modules/@flex-development/trext/esm/trext.mjs:113:3
    at ModuleJob.run (node:internal/modules/esm/module_job:175:25)
    at async Loader.import (node:internal/modules/esm/loader:178:24)
    at async Object.loadESM (node:internal/process/esm_loader:68:5)
/******/    // Execute the module function
/******/    var threw = true;
/******/    try {
/******/        __webpack_modules__[moduleId](module, module.exports, __nccwpck_require__);
/******/        threw = false;
/******/    } finally {
/******/        if(threw) delete __webpack_module_cache__[moduleId];
/******/    }

in my case, createRequire is only imported if i bundle src/index.ts instead (haven't tested it yet, but judging from the output i believe it works as expected).

calvinf commented 2 years ago

For my use case, I was using the sqlite and sqlite3 modules. I was able to avoid this error by leaving them external in my build command:

ncc build src/index.ts -m -s --target es2020 -e sqlite3 -e sqlite

I've got minify and source maps turned on. The relevant part for other folks should be the -e external flag.

ariran5 commented 2 years ago

same issue

chrisreddington commented 1 year ago

+1 - I believe I'm encountering this same issue - https://github.com/chrisreddington/rss-parser/pull/120

dmitrydutin commented 1 year ago

I have a similar problem

It seems that not all require() statements are replaced by __WEBPACK_EXTERNAL_createRequire(import.meta.url)("package_name");.

Fix

Example

// Before replacement
module.exports = eval("require")("@aws-sdk/signature-v4-crt");
module.exports = require("assert");
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("http2");

// After replacement
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("@aws-sdk/signature-v4-crt");
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("assert");
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("http2");

// After minification
e=>{e.exports=(0,o.createRequire)(import.meta.url)("@aws-sdk/signature-v4-crt")};
e=>{e.exports=(0,o.createRequire)(import.meta.url)("assert")};
e=>{e.exports=(0,o.createRequire)(import.meta.url)("http2")};

Comment: It looks like some require("package_name") are being replaced with eval("require")("package_name"). Perhaps this should also be replaced with __WEBPACK_EXTERNAL_createRequire(import.meta.url)("package_name");.

It looks like a very bad trick, but it works for me. You can try to automate this.

My package.json

{
  "main": "build/index.js",
  "type": "module",
  "scripts": {
    "start": "ts-node src/index.ts",
    "build": "ncc build src/index.ts -o build -m --license licenses.txt"
  },
  "dependencies": {
    "@actions/core": "1.10.0",
    "@aws-sdk/client-s3": "3.289.0",
    "mime-types": "2.1.35"
  },
  "devDependencies": {
    "@types/mime-types": "2.1.1",
    "@types/node": "18.15.0",
    "@vercel/ncc": "0.36.1",
    "ts-node": "10.9.1",
    "typescript": "4.9.5"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "build",
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "lib": ["ESNext"],
    "types": ["node"],
    "strict": true,
    "noImplicitAny": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "forceConsistentCasingInFileNames": true
  },
  "exclude": [
    "build",
    "node_modules"
  ],
  "ts-node": {
    "esm": true
  }
}
extravio commented 1 year ago

Same error when using ES6 in a GitHub action based on https://github.com/actions/javascript-action @vercel/ncc version 0.36.1

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 '/runner/_work/_actions/[...]/dist/status-check/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at eval (eval at 553 (file:///runner/_work/_actions/[...]/dist/webpack:/javascript-action/node_modules/@vercel/ncc/dist/ncc/@@notfound.js:1:1), <anonymous>:1:1)
    at Object.553 (file:///runner/_work/_actions/[...]/dist/webpack:/javascript-action/node_modules/@vercel/ncc/dist/ncc/@@notfound.js:1:1)
    at __nccwpck_require__ (file:///runner/_work/_actions/[...]/dist/webpack:/javascript-action/webpack/bootstrap:21:1)
    at file:///runner/_work/_actions/[...]/dist/status-check/index.js:2827:78
    at file:///runner/_work/_actions/[...]/dist/status-check/index.js:2859:3
    at ModuleJob.run (node:internal/modules/esm/module_job:193:25)
    at async Promise.all (index 0)
    at ESMLoader.import (node:internal/modules/esm/loader:530:24)
    at loadESM (node:internal/process/esm_loader:91:5)
    at handleMainPromise (node:internal/modules/run_main:65:12)

Any solution?

DheerajYarlagadda commented 1 year ago

npm install ncc@latest npx ncc build ./path/file2build.js -o . This has solved the issue for me.

extravio commented 1 year ago

npm install ncc@latest npx ncc build ./path/file2build.js -o . This has solved the issue for me.

I guess you mean:

npm install @vercel/ncc@latest

I'm using "@vercel/ncc@lastest" as well (0.36.1 right now) , with node 16.20.1

Minecraftschurli commented 1 year ago

This bug is nearly 2 years old. How is this not solved yet?

alepouna commented 11 months ago

This issue still happens, no official fixes yet?

pkerschbaum commented 11 months ago

Seems like I was able to apply a workaround for this problem: polyfilling require in ESM like this:

// File: "polyfill-require-in-esm.mjs"

/**
 * This ESM module polyfills "require".
 * It is needed e.g. when bundling ESM scripts via "@vercel/ncc" because of https://github.com/vercel/ncc/issues/791.
 */
import { createRequire } from 'node:module';
import url from 'node:url';

const __filename = url.fileURLToPath(import.meta.url);
globalThis.require = createRequire(__filename);
// File: "my-script.mjs"
import './polyfill-require-in-esm.mjs';

// now do everything else, importing other packages and stuff
extravio commented 11 months ago

Seems like I was able to apply a workaround for this problem: polyfilling require in ESM like this:

I've tried your workaround but it didn't work for me unfortunately

I still get

This file is being treated as an ES module because it has a '.js' file extension and '/.../dist/status-check/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at eval (eval at 553 (file:///.../dist/webpack:/javascript-action/node_modules/@vercel/ncc/dist/ncc/@@notfound.js:1:1), <anonymous>:1:1)
dforsber commented 8 months ago

This helped me (gnu sed in OSX "is" gsed).

gsed -i 's/module=>{module.exports=eval("require")("")}/module=>{module.exports={}}/g' index.js 
fregante commented 1 month ago

I found this piece of code in my build:

module.exports = eval("require")("@actions/cache");

This happened because @actions/cache was not installed in my dependencies.

I suggest looking into your build for any require calls.

Either way NCC should not output such eval("require") calls in ESM envs.

slavcodev commented 1 week ago

I found this piece of code in my build:

Thanks for the tip. In my case I hit this error because in my source code I had

import { App } from `./App`;

and the build contained

module.exports = eval("require")("./App");

changing it to

import { App } from `./App.js`;

fixed the problem :/