Visitar URL original
Loading node-fetch@3 in CJS and ESM · Issue #1279 · node-fetch/node-fetch · GitHub
Skip to content

Loading node-fetch@3 in CJS and ESM #1279

Closed

Description

@jimmywarting

Pure ESM package

node-fetch is an ESM-only module - you are not able to import it with require(). You don't necessary have to convert your hole project to ESM just b/c we did it. There are ways to load ESM modules in cjs package too (more about this in FAQ). You can also stay with the v2 branch - We will keep updating v2 with bug/security issues. But not so much with new features...

This means you have the following choices:

  1. Use ESM yourself. (preferred)
    Use import fetch from 'node-fetch' instead of const fetch = require('node-fetch') to import the package. You also need to put "type": "module" in your package.json and more. Follow the below guide.
  2. you could use async import(…) from CommonJS instead of require(…). This is supported in CommonJS also
  3. Stay on the existing version of the package until you can move to ESM.

You also need to make sure you're on the latest minor version of Node.js. At minimum Node.js 12.20, 14.14, or 16.0.

I would strongly recommend moving to ESM. ESM can still import CommonJS packages, but CommonJS packages cannot import ESM packages synchronously.

ESM is natively supported by Node.js 12.17 and later.

FAQ


Have questions about another tools? look trough other issues or ask new ones
We will continue to update this with new solutions from other accepted answers

Activity

  1. locked as too heated and limited conversation to collaborators on Sep 8, 2021
  2. pinned this issue on Sep 8, 2021
  3. changed the title [-]Loading node-fetch@3 in cjs/esm[/-] [+]Loading node-fetch@3 in CJS and ESM[/+] on Sep 8, 2021
  4. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    How can I move my CommonJS project to ESM?

    • Add "type": "module" to your package.json.
    • Replace "main": "index.js" with "exports": "./index.js" in your package.json.
    • Update the "engines" field in package.json to Node.js 12: "node": "^12.20.0 || >=14.13.1".
    • Remove 'use strict'; from all JavaScript files.
    • Replace all require()/module.export with import/export.
    • Use only full relative file paths for imports: import x from '.'; → import x from './index.js';.
    • If you have a TypeScript type definition (for example, index.d.ts), update it to use ESM imports/exports.
    • Optional but recommended, use the node: protocol for imports.
  5. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    Can I import ESM packages in my CJS project?

    Yes, but only asynchronous. The async import('node-fetch') function is supported in CJS contexts too (in v12.17).
    if you would like you can create a wrapper function:

    const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));

    (the next request won't re-import node-fetch cuz modules gets cached)
    This can make the Node process boot up faster and only lazy loads the node-fetch when it's needed

    Another way to preload node-fetch could be to:

    const fetchPromise = import('node-fetch').then(mod => mod.default)
    const fetch = (...args) => fetchPromise.then(fetch => fetch(...args))

    if your bundler rewrites your async import to require: then have a look at:
    TypeScript/WebPack rewrites my async imports to require in CJS projects

  6. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    How do I get typing support if I'm using async import?

    For TypeScript users who are only after the Types, you can do: Type-Only Imports

    import type fetch, { Request } from 'node-fetch' 

    (this will not import or transpile anything - this typing annotation will just be discarded)

    for JSDoc users, this can work:

    /**
     * @typedef {import('node-fetch').Request} Request
     * @typedef {import('node-fetch').Response} Response
     */
  7. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    Can I import ESM packages in my TypeScript project?

    Yes, but you need to convert your project to output ESM. See below.

  8. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    How can I make my TypeScript project output ESM?

    • Add "type": "module" to your package.json.
    • Replace "main": "index.js" with "exports": "./index.js" in your package.json.
    • Update the "engines" field in package.json to Node.js 12: "node": "^12.20.0 || >=14.13.1".
    • Add "module": "ES2020" to your tsconfig.json.
    • Use only full relative file paths for imports: import x from '.'; → import x from './index.js';.
    • Remove namespace usage and use export instead.
    • Optional but recommended, use the node: protocol for imports.
    • You must use a .js extension in relative imports even though you're importing .ts files.

    If you use ts-node, follow this guide.

  9. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    I'm having problems with ESM and TypeScript

    If you have decided to make your project ESM ("type": "module" in your package.json), make sure you have "module": "ES2020" in your tsconfig.json and that all your import statements to local files use the .js extension, not .ts or no extension.

  10. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    TypeScript/WebPack/esbuild/rollup rewrites my async import() to require() in CJS projects

    If you have something like this async import:

    const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args))

    But it will be builded into this require statement

    const fetch = (...args) => Promise.resolve().then(() => __importStar(require('node-fetch'))).then(({ default: fetch }) => fetch(...args))

    Then you can do:

    const _importDynamic = new Function('modulePath', 'return import(modulePath)')
    
    async function fetch(...args) {
      const {default: fetch} = await _importDynamic('node-fetch'))
      return fetch(...args))
    }

    which is used to an encapsulated addition for loading ESM via dynamic import or require for non-ESM code

    If you want this to be fixed in TypeScript, vote for this issue to be fixed:
    microsoft/TypeScript#43329


    An alternative solution could be to include a file that typescript compiler won't touch, then you need to add allowJs: true (Maybe you also need to add a entry point to exclude)

    // fetch.js
    module.export = const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args))
    
    // tsconfig.json
    { "allowJs": true, "checkJs": true }
    
    // main.ts
    import fetch from './fetch.js'
  11. jimmywarting commented on Sep 8, 2021

    @jimmywarting
    CollaboratorAuthor

    I'm having problems with ESM and ts-node

    Follow this guide and ensure you are on the latest version of ts-node.

  12. jimmywarting commented on Sep 20, 2021

    @jimmywarting
    CollaboratorAuthor

    Can I run a ESM file/project without a package.json?

    Yes. Even if you don't have a package.json and no "type": "module" then it's possible to use the --input-type flag or change the filename to .esm

    Node.js treats JavaScript code as CommonJS modules by default. Authors can tell Node.js to treat JavaScript code as ECMAScript modules via the .mjs file extension, the package.json "type" field, or the --input-type flag. See Modules: Packages for more details.

    https://nodejs.org/api/packages.html#packages_determining_module_system

  13. jimmywarting commented on Oct 12, 2022

    @jimmywarting
    CollaboratorAuthor

    if typescript is rewriting your import statement to require()
    then you could also try

    const _importDynamic = new Function('modulePath', 'return import(modulePath)')
    
    async function fetch(...args) {
      const {default: fetch} = await _importDynamic('node-fetch'))
      return fetch(...args))
    }

    or just update to latest NodeJS version (v18+) that has fetch built in

    You can also install node-fetch v2 that is still in cjs format

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions