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

Unable to import/use "write-pkg" package #906

Closed
prakashraman opened this issue Jun 24, 2022 · 3 comments · Fixed by oclif/core#759
Closed

Unable to import/use "write-pkg" package #906

prakashraman opened this issue Jun 24, 2022 · 3 comments · Fixed by oclif/core#759
Labels
ESM Related to ESM support

Comments

@prakashraman
Copy link

prakashraman commented Jun 24, 2022

Hi,

While attempting to import and use the write-pkg package in a command I see the following error

(node:77206) [ERR_REQUIRE_ESM] Error Plugin: cli [ERR_REQUIRE_ESM]: require() of 
ES Module <command-file-path> from <command-file-path>

Instead change the require of index.js in <command-file-path> to a dynamic import() which
is available in all CommonJS modules.

The code

import { writePackage } from "write-pkg";

...
writePackage(<filepath>, {foo: "bar"})

Run

./bin/dev <command>

Any thoughts?

@0xdevalias
Copy link

0xdevalias commented Aug 10, 2022

@prakashraman This may be a dumb question, but does your package.json have "type": "module" defined as per these StackOverflow answers? (Edit: I explored this (see 'DeepDive' section below), but it ultimately didn't lead to me solving the issue.


Potentially Related

DeepDive

I tried to replicate this as follows:

Details
⇒  npx oclif generate fooCli

     _-----_
    |       |    ╭──────────────────────────╮
    |--(o)--|    │  Time to build an oclif  │
   `---------´   │    CLI! Version: 3.1.2   │
    ( _´U`_ )    ╰──────────────────────────╯
    /___A___\   /
     |  ~  |
   __'.___.'__
 ´   `  |° ´ Y `

Cloning into '/Users/devalias/dev/tmp/fooCli'...

..snip..

Created fooCli in /Users/devalias/dev/tmp/fooCli

```shell
cd fooCli
⇒  npm i write-pkg
..snip..

⇒  npm ls write-pkg
[email protected] /Users/devalias/dev/tmp/fooCli
└── [email protected]
diff --git a/src/commands/hello/index.ts b/src/commands/hello/index.ts
index 2b551c9..7fd49f5 100644
--- a/src/commands/hello/index.ts
+++ b/src/commands/hello/index.ts
@@ -1,4 +1,5 @@
 import {Command, Flags} from '@oclif/core'
+import { writePackage } from "write-pkg";
 
 export default class Hello extends Command {
   static description = 'Say hello'
@@ -19,5 +20,7 @@ hello friend from oclif! (./src/commands/hello/index.ts)
     const {args, flags} = await this.parse(Hello)
 
     this.log(`hello ${args.person} from ${flags.from}! (./src/commands/hello/index.ts)`)
+
+    writePackage("package.json", {foo: "bar"})
   }
 }
⇒  ./bin/dev hello
(node:64842) [ERR_REQUIRE_ESM] Error Plugin: fooCli [ERR_REQUIRE_ESM]: require() of ES Module /Users/devalias/dev/tmp/fooCli/node_modules/write-pkg/index.js from /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts not supported.
Instead change the require of index.js in /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts to a dynamic import() which is available in all CommonJS modules.
module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
(Use `node --trace-warnings ...` to show where the warning was created)
Say hello to the world and others

USAGE
  $ fooCli hello COMMAND

COMMANDS
  hello world  Say hello world

Which gave me the following more specific error:

(node:64842) [ERR_REQUIRE_ESM] Error Plugin: fooCli [ERR_REQUIRE_ESM]: require() of ES Module /Users/devalias/dev/tmp/fooCli/node_modules/write-pkg/index.js from  /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts not supported.
Instead change the require of index.js in /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts to a dynamic import() which is available in all CommonJS modules.
module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
(Use `node --trace-warnings ...` to show where the warning was created)

Looking in my generated CLI's package.json, there doesn't appear to be a "type": "module" defined, though adding it just leads to a different error being displayed:

⇒  ./bin/dev hello
node:internal/errors:465
    ErrorCaptureStackTrace(err);
    ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for /Users/devalias/dev/tmp/fooCli/bin/dev. Loading extensionless files is not supported inside of "type":"module" package.json contexts. The package.json file /Users/devalias/dev/tmp/fooCli/package.json caused this "type":"module" context. Try changing /Users/devalias/dev/tmp/fooCli/bin/dev to have a file extension. Note the "bin" field of package.json can point to a file with an extension, for example {"type":"module","bin":{"dev":"./bin/dev.js"}}
    at new NodeError (node:internal/errors:372:5)
    at Object.getFileProtocolModuleFormat [as file:] (node:internal/modules/esm/get_format:76:11)
    at defaultGetFormat (node:internal/modules/esm/get_format:118:38)
    at defaultLoad (node:internal/modules/esm/load:21:20)
    at ESMLoader.load (node:internal/modules/esm/loader:407:26)
    at ESMLoader.moduleProvider (node:internal/modules/esm/loader:326:22)
    at new ModuleJob (node:internal/modules/esm/module_job:66:26)
    at ESMLoader.#createModuleJob (node:internal/modules/esm/loader:345:17)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:304:34)
    at async Promise.all (index 0) {
  code: 'ERR_UNKNOWN_FILE_EXTENSION'
}

Adding a .js extension to ./bin/dev results in this error:

⇒  ./bin/dev.js hello
file:///Users/devalias/dev/tmp/fooCli/bin/dev.js:3
const oclif = require('@oclif/core')
              ^

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 '/Users/devalias/dev/tmp/fooCli/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
    at file:///Users/devalias/dev/tmp/fooCli/bin/dev.js:3:15
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

Changing it to a .cjs extension results in this error:

⇒  ./bin/dev.cjs hello
(node:66429) [ERR_REQUIRE_ESM] Error Plugin: fooCli: Must use import to load ES Module: /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts
require() of ES modules is not supported.
require() of /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts from /Users/devalias/dev/tmp/fooCli/node_modules/@oclif/core/lib/module-loader.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/devalias/dev/tmp/fooCli/package.json.

module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
(Use `node --trace-warnings ...` to show where the warning was created)
(node:66429) [ERR_REQUIRE_ESM] Error Plugin: fooCli: Must use import to load ES Module: /Users/devalias/dev/tmp/fooCli/src/commands/hello/world.ts
require() of ES modules is not supported.
require() of /Users/devalias/dev/tmp/fooCli/src/commands/hello/world.ts from /Users/devalias/dev/tmp/fooCli/node_modules/@oclif/core/lib/module-loader.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/devalias/dev/tmp/fooCli/package.json.

module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
Say hello to the world and others

USAGE
  $ fooCli hello COMMAND

Going back to the drawing board.. I removed "type": "module" and tried using the dynamic import syntax as suggested in the errors:

Diff
diff --git a/src/commands/hello/index.ts b/src/commands/hello/index.ts
index 2b551c9..93b2342 100644
--- a/src/commands/hello/index.ts
+++ b/src/commands/hello/index.ts
@@ -1,5 +1,7 @@
 import {Command, Flags} from '@oclif/core'
 
+const writePackagePromise = import('write-pkg').then(({ writePackage }) => writePackage);
+
 export default class Hello extends Command {
   static description = 'Say hello'
 
@@ -19,5 +21,8 @@ hello friend from oclif! (./src/commands/hello/index.ts)
     const {args, flags} = await this.parse(Hello)
 
     this.log(`hello ${args.person} from ${flags.from}! (./src/commands/hello/index.ts)`)
+
+    const writePackage = await writePackagePromise
+    writePackage("package.json", {foo: "bar"})
   }
 }

But this still gave me errors:

⇒  ./bin/dev hello
Error [ERR_REQUIRE_ESM]: require() of ES Module /Users/devalias/dev/tmp/fooCli/node_modules/write-pkg/index.js from /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts not supported.
Instead change the require of index.js in /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts to a dynamic import() which is available in all CommonJS modules.
    at /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts:4:58 {
  code: 'ERR_REQUIRE_ESM'
}

It was suggested in #695 that perhaps this is related to how ts-node is handling things. Based on that, i found the following issues that sound related:

@0xdevalias
Copy link

I tried following along with the esm instructions from the following:

But ended up with the following errors:

Details
⇒  yarn ts-node-esm bin/dev
yarn run v1.22.19
$ /Users/devalias/dev/tmp/fooCli/node_modules/.bin/ts-node-esm bin/dev
(node:7005) [ERR_REQUIRE_ESM] Error Plugin: fooCli: Must use import to load ES Module: /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts
require() of ES modules is not supported.
require() of /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts from /Users/devalias/dev/tmp/fooCli/node_modules/@oclif/core/lib/module-loader.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/devalias/dev/tmp/fooCli/package.json.

module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
(Use `node --trace-warnings ...` to show where the warning was created)
(node:7005) [ERR_REQUIRE_ESM] Error Plugin: fooCli: Must use import to load ES Module: /Users/devalias/dev/tmp/fooCli/src/commands/hello/world.ts
require() of ES modules is not supported.
require() of /Users/devalias/dev/tmp/fooCli/src/commands/hello/world.ts from /Users/devalias/dev/tmp/fooCli/node_modules/@oclif/core/lib/module-loader.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/devalias/dev/tmp/fooCli/package.json.

module: @oclif/[email protected]
task: toCached
plugin: fooCli
root: /Users/devalias/dev/tmp/fooCli
See more details with DEBUG=*
oclif example Hello World CLI

VERSION
  fooCli/0.0.0 darwin-x64 node-v16.15.1

USAGE
  $ fooCli [COMMAND]

TOPICS
  plugins  List installed plugins.

COMMANDS
  help     Display help for fooCli.
  plugins  List installed plugins.

✨  Done in 0.81s.

Based on this error, I suspect that changes would need to be made in @oclif/core/lib/module-loader.js to be able to support CLI's as ESM modules, which I think nullifies the theory I had of using ts-node's esm mode:

require() of ES modules is not supported.
require() of /Users/devalias/dev/tmp/fooCli/src/commands/hello/index.ts from /Users/devalias/dev/tmp/fooCli/node_modules/@oclif/core/lib/module-loader.js is an ES module file as it is a .ts file whose nearest parent package.json contains "type": "module" which defines all .ts files in that package scope as ES modules.
Instead change the requiring code to use import(), or remove "type": "module" from /Users/devalias/dev/tmp/fooCli/package.json.

@mdonnalley mdonnalley added the ESM Related to ESM support label Jul 26, 2023
@mdonnalley mdonnalley moved this from Backlog to Waiting in ESM Support Aug 14, 2023
@mdonnalley
Copy link
Contributor

Fixed by oclif/core#759 (currently available in @ocilf/[email protected])

@github-project-automation github-project-automation bot moved this from Waiting to Closed in ESM Support Aug 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ESM Related to ESM support
Projects
No open projects
Status: Closed
Development

Successfully merging a pull request may close this issue.

3 participants