ai / nanoid

A tiny (124 bytes), secure, URL-friendly, unique string ID generator for JavaScript
https://zelark.github.io/nano-id-cc/
MIT License
24.73k stars 795 forks source link

v4 can't be imported in node #365

Open g012 opened 2 years ago

g012 commented 2 years ago

Hello,

I'm not knowledgeable at all in all the module formats / import mess of javascript / node, but I'm using KeystoneJS and I import nanoid in it. Since version 4 (2 days ago), I have this error :

Error [ERR_REQUIRE_ESM]: require() of ES Module /node_modules/nanoid/async/index.js from schema.ts not supported. Instead change the require of index.js in schema.ts to a dynamic import() which is available in all CommonJS modules.

This is how I've always imported nanoid :

import { nanoid } from 'nanoid/async';

Reverting to 3.3.4 works. I see in the commit comment that you removed CJS support, but as I understand, using this import statement, I'm using the new thingy module stuff, not CJS which uses require instead, and you have "type: module" in your package.json, so I really don't know what's wrong here.

Any idea what I'm doing wrong ? Thanks !

PoProstuWitold commented 2 years ago

I'm also having this issue

marekkobida commented 2 years ago

Me too.

danielweck commented 2 years ago

This is a feature, not a bug. See the changelog for details of the breaking change in version 4.0 (semantic versioning major increment): https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40

danielweck commented 2 years ago

Also see the author's feedback in this previously-closed issue: https://github.com/ai/nanoid/issues/364#issuecomment-1150173952

ai commented 2 years ago

Check your TS config.

Seems like TS convert import in source TS sources to require. I use this option in tsconfig.json: "module": "esnext" (buy you may need to convert the whole app to TS).

g012 commented 2 years ago

This is a feature, not a bug. See the changelog for details of the breaking change in version 4.0 (semantic versioning major increment): https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40

This doesn't help at all, we saw the comment in the commit on main page of code repo, as stated.

Also see the author's feedback in this previously-closed issue: #364 (comment)

In this one the guy says he was using require, and is told to move to import. As stated, I (we ?) are already using import since long.

Check your TS config.

Seems like TS convert import in source TS sources to require. I use this option in tsconfig.json: "module": "esnext" (buy you may need to convert the whole app to TS).

Thanks, I've tried changing module: "commonjs" to module: "esnext", but it made no difference. Could you share your whole tsconfig file ? Here's mine:

  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "jsx": "react"
  }
}
ai commented 2 years ago

Maybe you should remove "esModuleInterop": true,. Try to call tcs file.ts to be sure that you have import in the compiled results.

Here is one of my examples https://github.com/hplush/slowreader/blob/main/tsconfig.json

danielweck commented 2 years ago

Hello @g012 , have you seen this doc? https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

Support for ESM depends heavily on tooling, for example you may have different tsconfig.json settings for your unit tests, your dev builds, and your production release ... depending on whether your codebase is managed with WebPack, Rollup, Vite, Jest, Vitest, etc.

The author of NanoID said that he will kindly continue to offer off-the-shelf compatibility with CommonJS by maintaining v3 in parallel to ESM v4, but I am concerned that noise/signal ratio will increase in this issue tracker due to v4 support queries.

As far as I can tell there are no problems with NanoID's published package.json export map etc. so I think it would make sense to continue such general ESM/CJS conversations in a GitHub discussion instead.

:)

amir-arad commented 2 years ago

I'm having the same issue in two flavors. first one was described above. second one is:

 Details:

    /home/circleci/project/node_modules/nanoid/index.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,jest){import { randomFillSync } from 'crypto'
                                                                                      ^^^^^^

    SyntaxError: Cannot use import statement outside a module

    > 1 | import { customAlphabet } from 'nanoid';
        | ^
      2 |
      3 | const letters = customAlphabet('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 1);
      4 | const alphanumeric = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', 5);

in short, I need to turn on an experimental feature in node to enable ESModules import in Jest. I can't wait for ESModules to become a standard, but right now it's not yet frictionless.

this is my update PR: starwards/starwards#847

picardplaisimond commented 2 years ago

I think this decision was made far too early. ESM has just started to be supported by NodeJS. I'm not sure if I want to refactor my whole "production application" for ESM right now.

I just wanted to point that out.

danielweck commented 2 years ago

. I'm not sure if I want to refactor my whole "production application" for ESM right now.

"We will support 3.x branch with CommonJS for users who can’t migrate to ESM"

https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40

g012 commented 2 years ago

Hello @g012 , have you seen this doc? https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c

Support for ESM depends heavily on tooling, for example you may have different tsconfig.json settings for your unit tests, your dev builds, and your production release ... depending on whether your codebase is managed with WebPack, Rollup, Vite, Jest, Vitest, etc.

The author of NanoID said that he will kindly continue to offer off-the-shelf compatibility with CommonJS by maintaining v3 in parallel to ESM v4, but I am concerned that noise/signal ratio will increase in this issue tracker due to v4 support queries.

As far as I can tell there are no problems with NanoID's published package.json export map etc. so I think it would make sense to continue such general ESM/CJS conversations in a GitHub discussion instead.

:)

Hi Daniel,

Yes I think you're right, the Keystone JS toolset converts typescript to CJS, and if I disable that, I get lint warnings for k6 core and some others, so I've decided to stick with branch 3 until everything migrates.

Thanks for the help !

garretthogan commented 2 years ago

This is a feature, not a bug. See the changelog for details of the breaking change in version 4.0 (semantic versioning major increment): https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40

Really terrible decision. Was gonna use this in place of shortid because apparently this is more secure? But since I literally can't import the latest I'm just gonna keep using shortid. Good luck building a product that people can't use!

danielweck commented 2 years ago

... since I literally can't import the latest I'm just gonna keep using shortid.

"We will support 3.x branch with CommonJS for users who can’t migrate to ESM"

https://github.com/ai/nanoid/blob/main/CHANGELOG.md#40

weyert commented 2 years ago

Are you planning any security updates for 3.x? Can you clarify what you mean with 'support 3.x branch'?

ai commented 2 years ago

Are you planning any security updates for 3.x? Can you clarify what you mean with 'support 3.x branch'?

Of course. All fixes will be backported.

ayushsharma82 commented 2 years ago

Use this version while the author fixes commonjs issue:

npm i -S nanoid@^3.0.0
weyert commented 2 years ago

Whatever works for the maintainer. I am happy the person still maintains the CommonJS version for security updates :)

ai commented 2 years ago

Theres no harm in supporting commonJS neither does it has any performance ,build or maintainability problems. Its too early to move into ESM imo

Dual ESM/CJS packages is not a good thing. As a developer of dual-publish I can say it without a doubt.

  1. You need to duplicate every file in npm package which increase node_modules size.
  2. It leads to expected problems in some non-standard systems (for instance, Jest is using custom ESM resolver and dual packages could increase the error rate).
  3. Dual packages requires extra build step (like dual-publish or babel). With ESM-only you can publish your repository directly.
  4. It also make more complex another tools. For instance, Size Limit will require extra plugin.
  5. There is no simple way to use version from repository (for instance, to test PR) without some painful bugs. Because dual packages requires build step.

Current state of ecosystem when we need to support both ESM and CJS is very hard for maintainers. Our community need to migrate to ESM-only future. It was already a few years since ESM announce.

Julusian commented 2 years ago

Current state of ecosystem when we need to support both ESM and CJS is very hard for maintainers.

That is true, but esm only packages can be very hard for users ;)

Im perfectly happy to keep using v3 until I can switch things to ESM (there is already a pretty long list of other dependencies that cant be updated), but that switch is currently impossible due to electron not supporting ESM in the backend at all, and jest needing nodejs to finish some features before they can have feature parity with CJS. I personally would have no problem with libraries pushing users to ESM if nodejs & electron were ready for it. But they aren't, so even though ESM has been around for years, the push from library authors feels premature to me.

ai commented 2 years ago

I personally would have no problem with libraries pushing users to ESM if nodejs & electron were ready for it

Electron and Node.js will not be ready for years if there will not be push from the community.

It is better to support ESM issues in Electron and Node.js.

Im perfectly happy to keep using v3 until I can switch things to ESM

You do not need to always use the latest version of the dependency. You need to use the latest supported version. Both branches 3.x and 4.x are supported. Don’t worry that you are on 3.x branch.

weyert commented 2 years ago

I don't really mind maintainers of packages switching to ESM. It's their project. Only I wish they don't forget their old CommonJS packages when vulnerabilities in dependencies or similar occur. So I was glad to hear this is the case for this super useful package :)

I really need to find out how I can get ESM modules working with Jest. Or is there a better alternative for Jest that has better ESM support? Anyone tried Vitest? Looks like its compatible with Jest's expect?

ai commented 2 years ago

Or is there a better alternative for Jest that has better ESM support?

For simple Node.js libraries uvu is better.

For React projects Vitest is the best option.

Julusian commented 2 years ago

You do not need to always use the latest version of the dependency. You need to use the latest supported version. Both branches 3.x and 4.x are supported. Don’t worry that you are on 3.x branch.

Exactly. Im using 4.x in some projects and 3.x in others, depending on whether they are ESM or not. Hopefully 3.x will get updates for a few years, as I expect ESM wont be usable for everyone for at least a couple more years

I really need to find out how I can get ESM modules working with Jest. Or is there a better alternative for Jest that has better ESM support? Anyone tried Vitest? Looks like its compatible with Jest's expect?

I believe that Jest does mostly work, but they don't have feature parity with CJS. https://github.com/facebook/jest/issues/9430 The main blocker for me is the lack of mock support, which I believe is blocked on the required nodejs features still being experimental.

dannyglovory commented 2 years ago

Use this version while the author fixes commonjs issue:

npm i -S nanoid@^3.0.0

Thank you, it's works for me

ai commented 2 years ago

Just stay on Nano ID 3 if you have CJS project. We will support Nano ID 3 for a few years.

I delete a very hacky and dangerous advice of crazy wraps to load ESM to CJS.

jpike88 commented 2 years ago

No, I'm going to use v4 using the 'hacky and dangerous' method because I don't want to worry about being stuck on an obsolete version which will not be supported soon.

ai commented 2 years ago

I don't want to worry about being stuck on an obsolete version which will not be supported soon.

Nano ID 3 is not obsolete. It is a parallel version. We will support it for a few years.

Just use Nano ID 3.x. There are no rational problems with this version.

jpike88 commented 2 years ago

If a version of an open source node library has got an end of life announced for it, I consider it already on its way out. It's how I and many other devs out there work, and it's all about minimising technical debt.

That will be the only dependency of over 50 in my package.json I have to worry about pinning, which I've managed to avert worrying about by doing this 'super dangerous hack' (which isn't really that dangerous at all, I have an integration test that covers usage of it and continuously audit my packages).

The problem here isn't whether or not people should stay on v3 or not, it's about understanding the reality of many projects out there that do not have the resources or priorities around upgrading to ESM. ESM isn't a magical solution to dependency security, you can still do plenty of mischief whether your lib is used in CJS or ESM mode.

ai commented 2 years ago

If a version of an open source node library has got an end of life announced for it

There is no EOL announced for Nano ID 3.x.

For now, I am planning to support it util most of CJS users will use it.

it's about understanding the reality of many projects out there that do not have the resources or priorities around upgrading to ESM

You need to understand the complexity of dual CJS/ESM support. As a developer of dual-publish I found the true reality of how hard it is to support all edge cases just tried to support all of them.

jpike88 commented 2 years ago

This ESM/CJS nonsense is such a mess... how did they honestly not build interop into the spec, it's just causing pain and suffering for all involved.

I'll look into sticking with 3.x, its a great library and I'm sticking with it either way :)

weyert commented 2 years ago

Personally, I don’t have problems with ESM. I have been struggling to get libraries like got, react-markdown to work in Jest test files. That’s my main blocker for the switch. And now with the memory issue in latest Node 16 and/or Jest 28 it’s a struggle to upgrade to newer versions :(

neilfranci commented 2 years ago

Use this version while the author fixes commonjs issue:

npm i -S nanoid@^3.0.0

struggling to convert to ESM, I get random error, finding on StackOverflow nothing work. End up using

yarn add nanoid@3.3.4

I wish I could find some projects that use expressjs typescript with ESM module. Maybe 4.x just for client-side example React app

onesmusmuna commented 2 years ago

Just downgrade the package, it will work fine yarn add nanoid@3.3.4

SofiaPetinova commented 2 years ago

Hi! Have the same issue. I just change the version nanoid. version 3.0.0 instead of version 4.0.0 in package.json file.

sahdev0 commented 2 years ago

Could you try with this configuration in tsconfig complierOptions?

"target": "es2020", "module": "es2020"

dcsan commented 2 years ago

ESM is a disaster in typescript. so many projects have issues like this, eg node-fetch and others. for plain JS it's possible to convert over, but TS support is really patchy esp when you have modules inside other modules.

just hope nobody is using nano in another package as it will suddenly blow up

adiled commented 2 years ago

Good library, unfortunate release decision.. here I join the v3 gang.

ghost commented 2 years ago

I'm trying to use nanoid with TypeScript on nodejs and getting this error.

const nanoid_1 = require("nanoid");
                 ^

Error [ERR_REQUIRE_ESM]: require() of ES Module /opt/xxapi/node_modules/nanoid/index.js from /opt/xxapi/dist/controllers/auth/signup.js not supported.
Instead change the require of index.js in /opt/xxapi/dist/controllers/auth/signup.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/opt/xxapi/dist/controllers/auth/signup.js:25:18)
    at Object.<anonymous> (/opt/xxapi/dist/routes/auth.js:12:18)
    at Object.<anonymous> (/opt/xxapi/dist/index.js:7:32) {
  code: 'ERR_REQUIRE_ESM'
}

Node.js v18.7.0
ai commented 2 years ago

@bootrino you need to use pure ESM app in TS ("module": "esnext") to use Nano ID 4.

If you still convert TS app to CJS, use Nano ID 3.

ghost commented 2 years ago

OK, although I shouldn't need to reconfigure TypeScript to use a library.

johnf commented 2 years ago

@ai would you consider releasing an npm module called something likm nanoid-v3 or nanoid-cjs which tracks v3?

I only ask because I am a regular user of tools like yarn upgrade-interactive. It's going to constantly tell me that I can upgrade nanoid with the current approach

Yes, I'm one of those people that likes to keep everything at cutting edge

ai commented 2 years ago

It's going to constantly tell me that I can upgrade nanoid with the current approach

I have the same problem on my CJS projects (like PostCSS). I think we should not try to update always on latest version (or go to ESM if we want the latest solution).

malimccalla commented 2 years ago

Very strange. Is the only way to fix this downgrading to v3? I will do that for now.

ai commented 2 years ago

Is the only way to fix this downgrading to v3?

No. The best way is to move project to ESM.

If you use TS it means “true ESM” with "module": "esnext".

dcsan commented 2 years ago

no the best way is to use a less dogmatic package, esp if you're using TS, until the TS flow is a bit smoother.

for a greenfield JS project, starting with ESM is an option.

malimccalla commented 2 years ago

@ai Apologies, I don't really know what this means. I add new packages all the time, and this never seems to happen. We are using TS, but we have a project set up in a certain way, so unfortunately, we can't just 'move the project to ESM'. v3 works fine for me for now. Thanks

lvisb commented 2 years ago

It's a little painful, every time I need to update packages with npm-check-updates, I have to downgrade nanoid to version 3.X.X. I've already tried to migrate the project I'm working on to ESM, but many packages don't support it yet, too many errors that I don't think I can handle.

abdessamadpas commented 2 years ago

thanks got not only me

manumura commented 2 years ago

It's a little painful, every time I need to update packages with npm-check-updates, I have to downgrade nanoid to version 3.X.X. I've already tried to migrate the project I'm working on to ESM, but many packages don't support it yet, too many errors that I don't think I can handle.

With npm-check-updates, you can use -x option to exclude some dependency from the update, instead of updating then downgrading. For example to exclude nanoid:

ncu -u -x nanoid