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 !

rmirabelle commented 2 years ago

Attempting to change the module system (compilerOptions.module) from CommonJS to ESNext in tsconfig.json. doesn't work in Node.

It now appears all Node users will have to BOTH manually roll back to v3.3.4 AND begin looking for a replacement for this library as CommonJS has been permanently abandoned in v4.

Too bad it's so easy to accidentally or silently upgrade nano versions and break your entire build, as I did.

Julusian commented 2 years ago

Too bad it's so easy to accidentally or silently upgrade nano versions and break your entire build, as I did.

Luckily its just as easy to rollback to v3 and stick with that

rmirabelle commented 2 years ago

After all the time wasted chasing this, and after taking steps to attempt to warn all our developers that this library (and in our case, ONLY this library) can never be updated, you're right. It was pretty easy typing in a different version number. Of course, difficulty in rolling back was never the complaint.

Alfagun74 commented 2 years ago

this is terrible, any alternatives to this lib, not doing such bullshit? Why do good libraries like husky and this one always have to fuck it up somehow?

ai commented 2 years ago

Why do good libraries like husky and this one always have to fuck it up somehow?

Because moving to ESM is a global trend in JS ecosystem. It is better to join it.

francov commented 2 years ago

Are you aware that all packages dependent on your library are forced to adapt (right here, right now)? Isn't it better to add a build task that also generates the common js before publishing to npm?

ai commented 2 years ago

Isn't it better to add a build task that also generates the common js before publishing to npm?

We have it for 3.x release, and it took a lot of time to maintain and have problem for some edge cases.

dcsan commented 2 years ago

this is terrible, any alternatives to this lib, not doing such bullshit? Why do good libraries like husky and this one always have to fuck it up somehow?

agreed, this whole shift is zero benefit if you're typescript anyway and endless pain.

I use cuid on another react native project. I think it might have some similar ESM bs issues tho https://www.npmjs.com/package/cuid

natew commented 2 years ago

@ai I find your reasoning for not dual publishing unconvincing.

Export maps are part of the esm transition so your exact same reasoning for pushing esm and forcing the ecosystem to migrate applies there too. They are also far more supported than just plain old esm.

esbuild takes like some 10ms to build twice. And there’s tons of tools to use node register with that are trivial to use if you somehow are forced to import just esm.

And any analyzer worth its weight will need to support export maps to do so.

I’ve gone the dual publishing route and had no complains from tons of users so far. If you do it properly it supports both without and hiccups across all sorts of tools. And you avoid giant threads like this on your project.

The only downside is node_modules being slightly bigger.

ai commented 2 years ago

The only downside is node_modules being slightly bigger.

The downside is maintaince from the repository owner.

I do not have enough funding from my open source to spend extra time for both ESM and CJS versions.

natew commented 2 years ago

Fair. Not critiquing just thought I’d add perspective as someone doing it. Something like tsup or just a small script that runs esbuild twice typically works and can be added as a pre publish or commit hook.

FlorianWendelborn commented 2 years ago

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

This isn't true, unless you explicitly specify the dependency version as *.

ai commented 2 years ago

Something like tsup or just a small script that runs esbuild twice typically works and can be added as a pre publish or commit hook.

Just run esbuild will not work.

I created dual-publish and just check how many edge cases maintainer have to think about (Node, webpack, Node + TS, webpack + ts, esbuild, rollup, Parcel).

Maintaining cost is not when everything is working, but when it goes to edge cases.

bkniffler commented 2 years ago

And if you keep esm by default but allow to explicitly import from nanoid/cjs? At least I'd be able to alias in that case. Using nanoid in most cases works ok, but setting up jest to allow for certain packages to use esm is a pita in monorepos. Setting up an alias is much easier.

FlorianWendelborn commented 2 years ago

@bkniffler what’s even easier is just using nanoid@3

ai commented 2 years ago

And if you keep esm by default but allow to explicitly import from nanoid/cjs?

Maintaince cost will be again too big (for the feedback I have from the community).

michaelhays commented 2 years ago

For pnpm users who frequently use pnpm update --latest, they just added a configuration option for pnpm.updateConfig.ignoreDependencies in v7.13.0:

pnpm add nanoid@3
// package.json
{
  "pnpm": {
    "updateConfig": {
      "ignoreDependencies": ["nanoid"]
    }
  }
}
FlorianWendelborn commented 2 years ago

@michaelhays it’s nice that this exists, but this probably ignores 3.x releases as well. I doubt there’s much that can go catastrophically wrong in nanoid, but it’s something one should be aware of.

jacobsfletch commented 2 years ago

If you're coming here from React, v18 shipped the useId hook that might work for you.

stefanli commented 2 years ago

The entitlement from some of the assholes in this thread is unbelievable. I'm running into this issue myself and yes, it's causing some minor pain. But it would never occur to me to yell at the maintainer and demand changes. Show some fucking respect people.

moatorres commented 2 years ago

The only downside is node_modules being slightly bigger.

The downside is maintaince from the repository owner.

I do not have enough funding from my open source to spend extra time for both ESM and CJS versions.

Would you like me to create a PR with the build script for both ESM and CJS versions?

ai commented 2 years ago

Would you like me to create a PR with the build script for both ESM and CJS versions?

PR is not help. It will take me a week to then fix all possible issues and then I will spend a day every week answering people with rare Jest edge case.

I already wrote dual-publish build script (it is not so easy btw) but in some moment I found that it is just impossible to cover all edge cases.

iambumblehead commented 2 years ago

nanoid and express are my favorite packages of all time.

If this arm-chair comment is not useful, please excuse me. Possibly the build process could be simplified to enable cjs and esm. As mentioned here, If nanoid exports a single default, a cjs variant can be generated with sed.

cp nanoid.js nanoid.cjs && sed -i 's/export default/module.exports =/' nanoid.cjs

After form-urlencoded began using this approach, cjs/esm issues went away.

In the previous ticket, you did not want to try this approach because of risks. Since risks are already incurred, maybe the approach could be reconsidered.

amiralitaheri-it commented 2 years ago

same here

scientiststwin commented 2 years ago

same issue

esadalez commented 2 years ago

I have the same problem. I want to use the latest version available but it doesn't work :/

roniceyemeli commented 2 years ago

downgrading to version 3.3.4 worked for me, if it can help

maslow commented 2 years ago

Understand and respect the author's choice, even if I can downgrade to v3, I probably won't use this product again. Hope to find a good replacement soon.

conqr2 commented 2 years ago

💩

medz commented 1 year ago

To tell a joke, the software forces the platform to support his software to solve the problems encountered by users.

I found the author to be a double standard person. I hope that the "nanoid" package will no longer appear in my software, especially Node-based backend projects. At least most of the packages I use are built using TS, and support will gradually increase with platform upgrades. These packages developed using TS make my work happy. nanoid makes me desperate to find a replacement.

jsardev commented 1 year ago

So much hate, disrespect and general crying while you can just downgrade 1 version and have (almost) the exact same thing, as the only thing that you'd benefit from v4 is the reduced package size - which is actually a few bytes. There are no security fixes, no additional features that you'll miss. What's the point?

And that's not all! This repository is under MIT license so you can just grab it and have your own version if you rely so much on it. You can apply any security fixes that would come up to v4. And there's more! The package is basically a single 85 LOC file which you could adjust to do whatever you want it to do.

Unbelievable 🙄

zwjohn commented 1 year ago

Reverting back to 3.* works, however, I always update my packages to the latest version, and don't want to keep this one outdated. You can import the package using dynamic import and it works for version 4.0.0. Put this code in constructor or as part of your app's initialization.

  (async () => {
      const module = await (eval(`import('nanoid')`) as Promise<any>);
      const nanoid = module?.nanoid;
     console.log(nanoid && nanoid(10));
    })();
bobbyconnolly commented 1 year ago

In my case, I just needed to generated a random code. So I just did this instead:

const crypto = require('crypto');

function generateRandomCode(length, characterSet) {
  let code = '';
  for (let i = 0; i < length; i++) {
    const randomIndex = crypto.randomBytes(1)[0] % characterSet.length;
    code += characterSet[randomIndex];
  }
  return code;
}

// Example usage:
const characterSet = '349ACEFHKLMNPRTWXY';
const codeLength = 5;
const randomCode = generateRandomCode(codeLength, characterSet);
console.log(randomCode); // prints a random code of length 5
icai commented 1 year ago

the same problem in sequelize seeder esm script, try to use follow replace it.

import { v4 as uuid } from 'uuid'
const nanoid = (size) => {
  return uuid().replace(/-/g, '').slice(0, size)
} ​​​
sylvix commented 1 year ago

I was using this library for educational purposes to generate random IDs for a simple file-based database. Not anymore, I guess. I will just move to crypto.randomUUID() which is already built into Node.js.

markhughes commented 1 year ago

Use 3.3.4 if you need CommonJS support. Use 4.0.0 if you need ESM support.

Removed CommonJS support. Nano ID 4 will work only with ESM applications. We will support 3.x branch with CommonJS for users who can’t migrate to ESM.

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

Yuri-Lima commented 1 year ago

I was using this library for educational purposes to generate random IDs for a simple file-based database. Not anymore, I guess. I will just move to crypto.randomUUID() which is already built into Node.js.

Basically, I did the same as built-in would make more sense since may be a little more supportive.

tada5hi commented 1 year ago

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.

Since the files are only on the file system, I don't see this as a problem, since when bundling with webpack, rollup etc for a nuxt, next, svelte, ... app only the corresponding module file ( cjs or esm ) is included in the bundle.

  1. 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).

Yes, Jest causes problems more often, but I think you can take that into account before you start backporting changes.

  1. Dual packages requires extra build step (like dual-publish or babel). With ESM-only you can publish your repository directly.

But cjs, can be used in both a cjs and esm ecosystem. This is not the case with esm for top level imports.

  1. It also make more complex another tools. For instance, Size Limit will require extra plugin.
  2. 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.

True

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.

You are absolutely right, but I think the step, one should go only if e.g. NodeJs Esm no longer runs in expermintal mode.

jpike88 commented 1 year ago

Things will only have a chance of moving to ESM when nodejs starts enforcing it (which might as well be eternity), until then there's just not enough pressure to do it. Nobody is going to try and update/replace countless mini-libraries down the depedency chain just because of some developer activism. And that's all this is. Everyone has the right to publish open source libraries that output to only ESM or not, but CJS is here to stay and that's the reality.

To those who really don't want to use v3, you have two options:

tada5hi commented 1 year ago

@jpike88 I see it exactly the same way

ai commented 1 year ago

But cjs, can be used in both a cjs and esm ecosystem. This is not the case with esm for top level imports.

CJS can’t be used as module from URL:

import { nanoid } from 'https://cdn.jsdelivr.net/npm/nanoid/nanoid.js'

Also CJS has problems with named exports in some environments.

cstavaru commented 1 year ago

I ran into the same problem today.

I was also using the node-fetch package whose authors made the same mistake as nanoid: their current major version is ESM-only. Almost two years later since this change and their "old" CJS release is still downloaded 25 times more frequently than their current ESM-only release (you can check NPM stats).

I wish package authors would understand that people can't switch to ESM because this would mean breaking the vast majority of their current dependencies. Switching popular packages to ESM-only will end up causing pain to others for 5 years or so and with the shiny new bleeding-edge version being barely used. So a lose-lose situation.

The final solution to this kind of issue will probably be solved in the Javascript standard which must provide a compatible upgrade path without these showstopper compatibility issues.

sugoidesune commented 1 year ago

This should be front page on the readme because this is wasting a lot of peoples time.

ai commented 1 year ago

@sugoidesune it is in Install section of docs

https://github.com/ai/nanoid#install

eezing commented 1 year ago

@ai Thanks for choosing to support CommonJS in v3.

I tried converting a monorepo to ESM; builds and runs fine, but Jest blew up. No dice for now.

ai commented 1 year ago

@eezing this is why I moved from Jest

dcsan commented 1 year ago

@ai what did you move to? is there some other testing framework that works with nanoid ?

kehiy commented 1 year ago

thats worked for me : npm uninstall nanoid npm install nanoid@3.3.4

iambumblehead commented 1 year ago

@dcsan not ai, but want to share this opinion after using different test frameworks,

JoshMcCullough commented 1 year ago

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!

@garretthogan you should amend your comment, knowing that v3 will continue to support CommonJS, and v4 was clearly indicated to support only ESM.

Thank you @ai for supporting both!