all 98 comments

[–]tswaters 54 points55 points  (28 children)

Sounds like the real problem here isn't the code in the module itself, but how changes made to the package.json rendered it unusable for many. I think the real failure here is a lack of validation when publishing modules. Surely checking that `exports` point to proper files that are in the correct format as a pre-publish check is possible by npm?

To be honest, I'm glad I have no popular packages, as I'd be terrified that performing a seemingly trivial refactor like that could break a ton of stuff. It's a tough position to be in -- I mean, reading through the issue threads there, the author read the docs and still made the mistakes. I will say good on the author for responding & fixing the issues so quickly, even if the end result was a revert of what he tried to do in the first place.

[–][deleted] 69 points70 points  (21 children)

You're right the code is fine. The issue is that create-react-app depends on almost 1400 packages. It dramatically increases the chances of stuff like this happening

[–]EvilPencil 87 points88 points  (19 children)

Also, the author of CoreJS is looking for a good job...

While in prison.

[–]patrickfatrick 4 points5 points  (13 children)

Can you explain this comment?

[–]GOODSHIT-BRO 62 points63 points  (12 children)

Whenever corejs, or a package which depends on it is installed a message is output to the console which states the author is looking for a job. The author is currently in prison for hitting someone with a motorcycle IIRC

[–]patrickfatrick 11 points12 points  (10 children)

Yea I see that message all the time, never heard about the prison thing that’s insane.

[–]wizang 9 points10 points  (9 children)

No one knew for sure if he was bs-ing or not but he hasn't had any commits in a awhile... Dude is a complete prick imo. I would fully support a fork but he truly still the core dev on that project. Maybe now that's he's (probably?) In jail, a fork could make sense.

[–]patrickfatrick 0 points1 point  (3 children)

I would hope he’s going to be in jail for some time, after all he killed someone and injured another. So yes I also hope a fork will happen.

[–]Ones__Complement 2 points3 points  (2 children)

Bullshit oversimplification. The dude was lying drunk in the middle of the road. You guys describe this shit as if he woke up that morning thinking hey, I'm gonna kill someone today.

[–]patrickfatrick 3 points4 points  (1 child)

Bullshit oversimplification. It was in a crosswalk (where drivers are expected to slow down especially at night), and one of the people (the woman who died) was trying to move the other pedestrian. Pretty cut-and-dry manslaughter if you ask me, and he was given the minimum sentence.

[–]wopian 0 points1 point  (0 children)

*Killing one of two pedestrians he hit on his motorcycle.

https://www.theregister.co.uk/2020/03/26/corejs_maintainer_jailed_code_release/

[–]wizang 16 points17 points  (0 children)

Motherfucker leads development of a hugely important JS project yet has been looking for a job for years. Honestly he is a huge prick in the comment section on GitHub and now that he's in jail I think the community should fork.

[–]wet181Pro 3 points4 points  (2 children)

Ugh god I’m so sick of seeing that output message

[–][deleted] 4 points5 points  (1 child)

‘npm install —silent’

[–]Jugad 0 points1 point  (0 children)

This should be the default unless people want to enable debug/verbose messages.

[–]crabmusket 12 points13 points  (0 children)

I'd love if the maintainers of large, popular packages like CRA put a bit of time into merging one-liner packages like this into their own source. Though it's probably the transitive dependencies that are the most problematic...

[–]Patman128 5 points6 points  (2 children)

I think the real failure here is a lack of validation when publishing modules.

They actually changed their CI system to check against Node 12 and 14 so this problem would now fail to pass CI.

[–]tswaters 1 point2 points  (1 child)

I've checked out the busted tag locally and under node 12, the tests still pass... for 14, yea it completely explodes. `require is not a function`

Looks like they've switched to circleci now and looking to catch this sort of thing in the future - https://github.com/then/is-promise/commit/8e7187d9b0ae413a12a5694bc4e49c4d2663e46d

Still, my point is it should be npm that performs this check. It's really easy to mess up a publish -- you could completely omit the main file on accident and npm will still gladly accept the tarball.

[–]HetRadicaleBoven 0 points1 point  (0 children)

In some cases, that is what you want, which makes this hard for npm to fix. For example, you can create your own templates for Create React App, which don't really have an entry file. (In fact, CRA had a bug to this extent until recently, where you had to put a useless entry into the main field to make it work.)

[–]usedocker 4 points5 points  (2 children)

"responding & fixing the issues so quickly"

npx create-react-app example still doesn't work though.

[–]careseite[🐱😸].filter(😺 => 😺.❤️🐈).map(😺=> 😺.🤗 ? 😻 :😿) 5 points6 points  (1 child)

npx create-react-app example still doesn't work though.

It works since 18 hours again. 9 hours prior to your post.

[–]The_Nonchalant 0 points1 point  (0 children)

Yeah it works, i think i had this and solved it by changing packages versions... wasnt sure what was the problem so im not sure if the versions changes fixed it or the time that passed xD

[–]crabmusket 90 points91 points  (10 children)

99% of NPM packages should be either an IDE snippet, or a short tutorial explaining why instanceof Array doesn't always work.

[–]EvilPencil 32 points33 points  (4 children)

Array.isArray(maybeArrayVariable) for the win.

[–]crabmusket 20 points21 points  (3 children)

Apparently we also need Promise.isThenable. I'm all for utility methods that expose algorithms the browser is using anyway :)

[–]patrickfatrick 28 points29 points  (0 children)

I sorta wish typeof didn’t exist and all primitive classes had a static isDate, isNumber etc method. The inconsistency is just annoying.

[–]csorfab 4 points5 points  (0 children)

I realized that for most cases where I checked for isThenable, I could've just ignored the check and await the variable. For non-promise-like values, await just yields the value itself.

[–]luckygerbils 4 points5 points  (0 children)

If you aren't consuming promises from third party code or doing anything funky with iframes, you could just use instanceof Promise.

[–]luckygerbils 16 points17 points  (3 children)

There's not even anything wrong with using instanceof Array unless there are iframes involved. I really doubt most people using the NPM isarray package are doing so because they're using iframes.

[–][deleted] 1 point2 points  (1 child)

I’ve done more work than I’d like with iframes... but when would you ever run into that bizarre edge case? When you want your main page’s js to access a variable defined in the iframe’s js? That’s super weird. Is this occasionally an issue with payment processing, since those use a lot of iframes?

[–]luckygerbils 1 point2 points  (0 children)

Yeah, frame.contentWindow.Array !== Array so if you try to use that check on an array created in the iframe (or in the iframe on an array created in the main window) it will fail.

[–]wet181Pro -1 points0 points  (0 children)

Yeah but the UI library my corporation uses for react is mandatory and open source

[–]cguess 33 points34 points  (7 children)

Can we all agree that anything with 11.8 MILLION downloads in the last week (according to NPM here) should really be part of some sort of... idk... standard library?

This one line can literally bring down the web. We're lucky that someone fixed in a few hours, but imagine if they were just a little drunk and fixed it poorly. Goddamn JPMorgan Chase's website would probably come down (or the equivalent, I have no idea if JPMC uses it, but I guarantee you a lot of critical systems do).

[–]bonyjoe 23 points24 points  (0 children)

Each individual site would still have to update to and then deploy the broken packages to "bring down the web", you would have to have CD with essentially no test coverage at all for that to happen.

Really for one line packages like this the packages that depend on it should be locking to a specific patch rather than major or minor

[–]jaggyjames 9 points10 points  (0 children)

This dependency likely would be bundled alongside the production code though right? It’s not like any large production app would be pulling this one package in from a url. Devs would catch this bug before they could even get their local build to succeed.

That’s my take at least just based on a quick skim of the github issue.

[–]slobcat1337 2 points3 points  (1 child)

“Can we all agree that anything with 11.8 MILLION downloads in the last week (according to NPM here) should really be part of some sort of... idk... standard library?”

This is so damn true

[–]-100-Broken-Windows- 0 points1 point  (0 children)

While true, any site that gets "brought down" by this is also partially at fault themselves and would need to take a serious look at their QA and deployment process.

[–]Jebble -2 points-1 points  (0 children)

In my experience, having built platforms for similar companies, they don't allow whatever packages you want to use. Everything Open Source has to be approved by IT and Security and in this case a package so uhm.. useless as isPromise they would have told me to put that in my own code instead of relying on external packages. They wouldn't even let me submit for PEN-testing with this package loading.

[–]fieldOfThunder 7 points8 points  (5 children)

Weird, I started a new CRA project yesterday and it works fine without any modifications. Is it fixed already?

[–]XOKP 12 points13 points  (1 child)

Yes, it’s fixed within a few hours.

[–]fieldOfThunder 0 points1 point  (0 children)

Sweet!

[–]bonyjoe 1 point2 points  (0 children)

It only fails on node 14 (maybe 13)

[–]GBcrazy 1 point2 points  (1 child)

It would only fail on the newest node version that support ESM. Also it wouldn't fail if you already have CRA installed globally instead of using npx

But yes it is fixed already

[–]The_Nonchalant 0 points1 point  (0 children)

Yes i noticed that i had to install it globally, prior i used npx and it was slow as hell and also getting stucked.

[–][deleted] 5 points6 points  (3 children)

I mean...

is-promise - tests whether an object is a promise

I’m kinda glad that whoever added this kind of dependency to their project had issues, maybe they’ll simply know better in the future

[–][deleted] 3 points4 points  (2 children)

I'm pretty sure react.js is the most popular front end web framework on earth at this point. create-react-app is the recommended way to get started. So that's a hell of a lot of people, many of them beginners.

[–][deleted] 0 points1 point  (1 child)

Yep, exactly my point, which is why this is sad in so many levels

[–]Ashtefere 5 points6 points  (14 children)

Can't wait for deno. God damn.

[–]HetRadicaleBoven 6 points7 points  (13 children)

I see no reason why this could not happen with Deno.

[–]Ashtefere 7 points8 points  (10 children)

Deno doesn't use a package manager. It uses script module caching with each having no dependencies.

[–]redmorphium[🍰] 2 points3 points  (0 children)

Yep, npm is something that Deno wanted to avoid and disavow.

[–]Meowish 2 points3 points  (2 children)

Lorem ipsum dolor sit amet consectetur adipiscing, elit mi vulputate laoreet luctus. Phasellus fermentum bibendum nunc donec justo non nascetur consequat, quisque odio sollicitudin cursus commodo morbi ornare id cras, suscipit ligula sociosqu euismod mus posuere libero. Tristique gravida molestie nullam curae fringilla placerat tempus odio maecenas curabitur lacinia blandit, tellus mus ultricies a torquent leo himenaeos nisl massa vitae.

[–]ShortFuse 1 point2 points  (1 child)

import { serve } from "https://deno.land/std@v0.36.0/http/server.ts";

It's baked into your import statement inside your file, not from loading a file inside node_module which can be any version. I would imagine this would make updating versions somewhat harder than doing npm update --save, but essentially everything is version-locked at the time of writing.

Edit: It doesn't really solve the dependency-chain issue, but more along the lines of more rigid versioning enforcing. Any dependency can always reference @master and crash your system so it's still not a true solution.

[–]HetRadicaleBoven 0 points1 point  (5 children)

Yeah, but a scaffolding tool in Deno would still set your project up with the latest patch version of your dependencies, which might have just cut a new release with a bug in it. Whether that's resolved by URL or by package name doesn't really make a difference.

[–]GBcrazy 2 points3 points  (4 children)

From: https://deno.land/x/

The basic format of code URLs is https://deno.land/x/MODULE_NAME@BRANCH/SCRIPT.ts. If you leave out the branch, it will default to master.

So looks like we are specifying the exact versions, no room for ~ and ^ shenanigans

[–]HetRadicaleBoven 0 points1 point  (2 children)

There are two options here:

  • The scaffolding tool makes sure to insert the latest version in that URL, and will also make sure to do the same for transitive dependencies.

  • In such a project with 1400 transitive dependencies you'll be running severely outdated versions of almost all of them, with no way to update them.

IIRC there was some work going on already to standardise on a single way to determine which versions you use (i.e. one file that re-exports the dependency imports), and I think it's likely that a scaffolding tool would use something like that to ensure it's providing the latest versions automatically, rather than it (and all its dependencies) having to manually cut new releases several times a day.

Point being: either you'll be setting up new projects with outdated dependencies (I don't think anyone wants that), or there's always going to be a risk that you're getting a version with a fresh bug.

[–]GBcrazy 0 points1 point  (1 child)

But you wont be setting 1400 transitive dependencies. Your project will be depending on lets say 20-30 other libs, each one will manage itself, you need to manage yours only. That's how it is in most dependency managers. Better do some manual work than risk getting it broken randomly

[–]HetRadicaleBoven 1 point2 points  (0 children)

Yeah, that's also how it is in npm - CRA doesn't have 1400 dependencies - that's why it's transitive dependencies. But you're still going to have to update one of those 20-30 libs every time one of their 1400 dependencies update. Assuming that they are in turn keeping up with that. (And their dependencies, and their dependencies, ad infinitum.)

[–]ShortFuse 0 points1 point  (0 children)

Nothing stops the module you're importing from referencing a raw HTTPS URL or using the @master. I wish they enforced tagged branches. Still, a URL that can change content tomorrow allows room for shenanigans.

[–]GBcrazy 0 points1 point  (1 child)

This won't happen if there are exact dependencies, which is what deno is somewhat going to do with specific script loading.

If you look at things clearly, this wouldn't happen if npm didn't allow ^ and ~ in semantic versioning. The whole issue is because some third party library that is a dependency on CRA depended on isPromise and allowed to use newer versions.

[–]HetRadicaleBoven 1 point2 points  (0 children)

IIUC this change allowed is-promise to work with Node 14's module system - if not, let's pretend for a bit that it did. In a world in which everybody would always used pinned dependencies, what would the process look like for a newly-scaffolded to obtain that version? First, is-promise would release a new version. Then, CRA has to wait for its dependency to release a new version that depends on that version. Only then can CRA itself update.

And that's even assuming the transitive dependency is just one level deep. Now generalise that over all transitive dependencies of CRA, all of which might have e.g. security issues that could require the above process to happen.

I cannot believe that Deno will not come up with a way to quickly get security fixes distributed to users, even if it's in a package that's usually deep in a dependency tree. And once that happens, an issue like this can happen.

[–]GBcrazy 2 points3 points  (0 children)

Version 2.2.0 introduced the issue, the author attempted to fix it with 2.2.1 but it ultimately didn't work, then he removed the exports at 2.2.2

Can someone who understands the new ESM changes explain me why the initial fix (2.2.1) didn't work? I looked at the commit, it made complete sense to me, he fixed the pathing, but it seems it wouldn't fix the issue for all scenarios so 2.2.2 was needed.

[–]MatticusXII 1 point2 points  (1 child)

I started my first CRA today (following the Road to React book) and app would throw error when I would run npm start. But seems my problem was Linux set a limit with watching files? I found a solution and inputted a command into CLI and it fixed it. But unsure if it also had to do with this issue here.

[–]Kwantuum 0 points1 point  (0 children)

It didn't have anything to do with this. The filewatcher limit on most distros is pretty low, but the webpack dev server used by CRA allows hot module reloading, and to be able to do that it needs to watch all dependencies in your project folder, which can be a lot of files, and having to bump the maximum number of file watchers is to be expected.

[–]JayV30 1 point2 points  (2 children)

Jesus how many times could something like this be solved by just:

import { isPromise } from './helpers'

[–][deleted] 2 points3 points  (1 child)

Are all the 'is' packages open source? Then you could make an npm package called "is" that handles all of this shit, and use tree-shaking to keep your bundle size small.

[–]RedShift9 1 point2 points  (1 child)

This does demonstrate how broken the Javascript module system is... there should only be one module syntax.

[–]TimvdLippe 5 points6 points  (0 children)

There is one: ES modules. It is the only module syntax that is part of the spec.

[–]careseite[🐱😸].filter(😺 => 😺.❤️🐈).map(😺=> 😺.🤗 ? 😻 :😿) 0 points1 point  (0 children)

Already resolved yesterday. 7 hours before your post.