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.34k stars 789 forks source link

4.0 doesn't support require in nodeJS #364

Closed bitdom8 closed 2 years ago

bitdom8 commented 2 years ago

const { customAlphabet } = require('nanoid') ^

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\Administrator\Documents\serverws\node_modules.pnpm\nanoid@4.0.0\node_modules\nanoid\index.js from C:\Users\Administrator\Documents\serverws\routes.js not supported.

ai commented 2 years ago

Yes. It is indented. 4.0 removed CommonJS support (require()).

You can move your app to ESM a use import instead of require.

Or you can stack with 3.x branch. We will support 3.x for a year.

bitdom8 commented 2 years ago

Thanks you sir @ai

shellscape commented 2 years ago

@ai please consider using only CHANGELOG.md or Releases. Makes it super confusing to know where to go for info when both exist. There's also the matter of the CHANGELOG.md have far less information than what is provided in Releases for the 3.0 release.

Please also consider publishing 3.x versions under the latest-3 dist-tag.

The decision to go ESM only is really unfortunate and sad. Hobbyists and open source (e.g. package) developers will probably absorb this change without much issue. But the business world will not, and ending support for the package in CommonJS (just as Sindre and countless others have done) will ultimately hurt the ecosystem's biggest users; businesses. Hell, it took AWS a full year and a month to release Node v16 support. I'm sure I won't change your mind, but I've personally always admired you and your work, and I'm really disappointed in your decision.

ai commented 2 years ago

@shellscape businesses (even if they do not pay we still try to support them) will not have difference.

They still have CJS version of Nano ID 3. This version still have a good support. I am still using Nano ID 3 in PostCSS.

About what problem do you taking exactly?

shellscape commented 2 years ago

Yes, we'll continue to use the 3.x version branch as long as we're able to. And still grateful for that.

Or you can stack with 3.x branch. We will support 3.x for a year.

After a year, 3.x will no longer have support, and that's sad. Businesses will not be updated to ESM-only dependencies and codebases in that time.

My best-guess estimate, based on watching the ecosystem and commercial adoption since v0.10, is that it will take the ecosystem at least 5 more years to get there. I'm not suggesting you support 3.x for 5 years, only providing my take on adoption of ESM-only.

ai commented 2 years ago

We will support 3.x for a year.

It is not an exactly a year, but a year minimum.

Anyway I need Nano ID 3 in PostCSS.

ljharb commented 1 year ago

@ai can you elaborate on why this decision was made?

It's worth noting that every single module that's gone ESM-only has gotten virtually no adoption for those versions; you can check on their npm package page under the "versions" tab. nano, so far, has only 1.57% after 5 months; there are packages that have been made this change for almost 2 years with similarly low uptake.

ai commented 1 year ago

nano, so far, has only 1.57% after 5 months;

It doesn’t look a problem for me. For this small utility projects, not everyone should be on the latest 4.x branch. 3.x is still supported.

I am using 4.x in my ESM-only projects (like @logux/core) and happy with smaller node_modules footprint.

ljharb commented 1 year ago

@ai sure, that's fine. I'd still love to understand why you made this change.

ai commented 1 year ago

Sure, my personal reasons:

  1. I see “nano” projects as something small and very effective. Having duplicates for every file (for ESM and CJS versions) in npm package doesn’t satisfy this goal.
  2. Now I have only 2 types of projects: pure CJS (like postcss) and pure ESM (like most of nano* projects). Before 4.x I have 3 types and must to always remember using special tools for dual ESM/CJS packages.
  3. All my active project was moved to ESM (PostCSS and Autoprefixer are on maintenance). For me, it is OK to keep using 3.x on the projects on maintenance stage.
  4. I stop believing in open source community to be really extra care of every use case and invest my time there.
  5. Supporting 2 branches is for me a good compromise between “keeping project simple”, “simplify maintenance” and still have a solution for every user’s case. The only problem is esthetic problem of some users (who want to use only latest versions, but didn’t migrate to ESM), but I do not want to invest my time to it because of previous step.
ljharb commented 1 year ago

That all makes sense - but what’s the value of “pure esm” given that esm can import CJS?

ai commented 1 year ago

@ljharb originally we added ESM to use package from ESM-compatible CDNs and have destructor in import API import { customAlphabet } from 'nanoid'.

I am not sure that migration to CJS will keep project compatible with all edge cases. But maybe I am wrong.

ljharb commented 1 year ago

ESM can named-import from CJS if the CJS is babel-transpiled.

npm packages simply aren't (in any consistent sense) usable from a CDN without a build process; any such build process can easily handle CJS modules just as well as ESM modules. I agree that you can't get a no-build-process native ESM setup working with a CJS module, but since many, many 9's of npm packages are in CJS, that's not really a viable option anyways.

ai commented 1 year ago

ESM can named-import from CJS if the CJS is babel-transpiled.

  1. What does it mean?
  2. Where exactly it will work with 100% guarantee? I need to support Node.js, Parcel 1 & 2, webpack, Rollup, esbuild, Metro.

npm packages simply aren't (in any consistent sense) usable from a CDN without a build process

Nano ID not only can but even specially created to be served from the simplest CDN:

// Not sure that it works because of GitHub content-type
import { nanoid } from 'https://raw.githubusercontent.com/ai/nanoid/main/nanoid.js'

any such build process can easily handle CJS modules just as well as ESM modules

Are we 100% sure with it, and about what CDNs are we sure?

A lot of people were forced me to release CJS/ESM version (2.x→3.x) because they told that their ESM CDN supports only ESM packages.

ljharb commented 1 year ago

What does it mean?

node's ESM implementation uses https://npmjs.com/cjs-module-lexer to try to infer named imports from CJS files. It works especially well for transpiler output.

Where exactly it will work with 100% guarantee?

By definition, "what node does" is the correct thing, so if any of those bundlers don't support this, then they're broken :-) That said, I'm pretty sure all of these support this, or they wouldn't be able to support the majority of the ecosystem's existing practices.

Are we 100% sure with it, and about what CDNs are we sure?

I'm 100% sure it could be done. I certainly haven't audited existing CDNs to figure out what capabilities they have (mostly because using CDNs isn't a best practice anymore - it's best to control the serving of your own assets).

There are only a very, very small number of authors that have chosen to publish ESM-only packages. If ESM CDNs want to gain adoption, they have no choice but to support CJS eventually anyways - why make life harder for your existing consumers in the meantime by switching to ESM-only? "ESM CDN" is a much less important use case than "every existing node user who uses your package", I'd expect.

shellscape commented 1 year ago

For what it's worth, here's everything Sindre has compiled on his move to ESM for all of his stuff: https://github.com/sindresorhus/meta/discussions/15. @wooorm as done the same for rehype/remark/unified and supporting packages as well. I don't like it and don't agree with their reasoning, but it's more than a handful of packages affected.

ljharb commented 1 year ago

@shellscape indeed, but it's still only a handful of authors

ai commented 1 year ago

By definition, "what node does" is the correct thing, so if any of those bundlers don't support this, then they're broken :-)

@ljharb :D. On one hand I have “3.x ESM+CJS & 4.x ESM” solution which works perfectly and has a single problem of not be so beautiful for CJS cases.

On another hand, I have months of my life spending fixing many edge cases (which we already fixed for 3.x) for rare bundlers and ESM CDNs.

I think you see the reason of why I prefer to keep it. Update to 4.x if you want to use latest versions. CJS is outdated too.

ljharb commented 1 year ago

CJS isn’t outdated; it’s a first-class module system for node, and will be supported for the foreseeable future - ESM will one day reach feature parity with CJS, although it’s not there yet.

I’m sorry you had to spend so much time on v4; i maintain hundreds of packages that are just CJS and haven’t had to spend any time on supporting ESM for them ¯\_(ツ)_/¯

wooorm commented 1 year ago

Fun! Another thread! 😅

It's worth noting that every single module that's gone ESM-only has gotten virtually no adoption for those versions; you can check on their npm package page under the "versions" tab. nano, so far, has only 1.57% after 5 months; there are packages that have been made this change for almost 2 years with similarly low uptake. — @ljharb

This is semver and the npm ecosystem working as designed. There is no reason why people must update in droves to a new major version in 5 months. Slower update cycles are fine. And download counts are terrible!

That’s like saying: hey, I made this new package, I just released it on npm last week, why doesn’t it have millions of downloads yet?!

what’s the value of “pure esm” given that esm can import CJS? — @ljharb

That is true in Node.js but not in other places.

it's still only a handful of authors — @ljharb

It’s… like… all the still active maintainers of lots of popular packages in the JavaScript world that don’t only care about Node.js.

CJS isn’t outdated — @ljharb

I’d argue it very much is. At least for folks that like JavaScript and not necessarily one particular runtime. And if not: it should be!

shellscape commented 1 year ago

I’m sorry you had to spend so much time on v4; i maintain hundreds of packages that are just CJS and haven’t had to spend any time on supporting ESM for them ¯_(ツ)_/¯

This just isn't constructive and unfortunately on-brand. Just zero need for that.

I don't agree with the decision to move to ESM-only, but I respect @ai and the decision he's made, especially so given the immense value he's contributed to the Node over the years. I credit him for maintaining the CJS branch in the meantime. I understand the arguments from him, Sindre and others, but I don't have to agree with them. They've all explained themselves thoroughly so we can gain perspective on their positions. At this point, that should be enough.

ljharb commented 1 year ago

@ai thanks for your explanation. I suspect you'll find that maintaining v3 and v4 is harder than shipping a dual package, and not maintaining v3 will mean folks have to find another solution but that'll be yours to discover :-)

nicopowa commented 1 year ago

here's how i fixed v4 with require. be careful not to call the method too soon because the import is asynchronous.

id.js

let id = null;

(async () => {

    const nanoid = await import("nanoid");
    const CustomAlphabet = nanoid.customAlphabet;
    const alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

    id = CustomAlphabet(alphabet, 12);

})();

module.exports = () => id();
const nanoid = require("./id.js");
//nanoid(); // crash, async import takes a few ms
setTimeout(() => console.log(nanoid()), 100); // working
shellscape commented 1 year ago

openbase.com now displays the ES Module support level (e.g. type of exports) on all of their package pages. If you're continually caught off guard by installing a dependency only to find out it's ESM-only, check the package out there first.

Screen Shot 2022-11-18 at 2 03 41 PM Screen Shot 2022-11-18 at 2 03 53 PM Screen Shot 2022-11-18 at 2 04 07 PM
ljharb commented 1 year ago

@shellscape since CJS also works in ESM, the only way something should show "CJS" is if it has a .node module.

shellscape commented 1 year ago

ljharb commented 1 year ago

lol no need to block me just for disagreeing with you ¯\_(ツ)_/¯

kehiy commented 1 year ago

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

glassdimlygr commented 1 year ago

@ai has been developing this project for a long time. If you want to assist in shipping a 4x branch that supports CJS, then perhaps you can step forward to help code it. Thank you for your work on this project, @ai.

shellscape commented 1 year ago

@ai doesn't need someone running to his defense. and we don't need another useless notification (I realize the irony in saying that whilst writing this comment which will generate a useless notification). Please virtue signal elsewhere.

Thank you for your work on this project, @ai.

yup. but next time, take it to twitter https://twitter.com/sitnikcode or sponsor him instead of leaving a comment on a closed issue.

nicopowa commented 1 year ago

— sorry useless reply — read and/or copy-paste my monkey patch above or use something else.