Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate from CommonJS to ESM #6651

Merged
merged 51 commits into from
Jul 9, 2021
Merged

Migrate from CommonJS to ESM #6651

merged 51 commits into from
Jul 9, 2021

Conversation

PyvesB
Copy link
Member

@PyvesB PyvesB commented Jun 20, 2021

Fixes #6528.

Our badge-maker package was left untouched, it is still a standard CommonJS module, which means there will be no impact on downstream consumers. The rest of the Shields.io codebase imports it as any other NPM package. The GitHub approve-bot action was left out as well, as it has its own separate package.json, it can be migrated in due course.

The automated tools I tried weren't very good, the best I found was Putout convert-commonjs-to-esm. As you'll see, a lot of manual fixing was required afterwards. Some parts of the code needed more changes than others, for example loader.js due to that fact that dynamically importing modules is asynchronous and the structure of imported modules is different. I've tried to break things down in commits describing my thought process, though I doubt reviewing each one individually will be very helpful.

Most test suites seem to be passing locally and the backend loads nicely and is able to service badges.

The frontend is where I'm stuck at the moment. I've got some local changes that should make it compliant once the general setup is working, but I'm struggling to get very far on that bit. The error I'm getting locally is along the following lines:

[frontend] TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for C:...\workspace\shields.cache\tmp-5248-0orlJ0tI72FY

If my understanding is correct the ESM loader is trying to load code generated by Gatsby, but Gatsby generated these files without any extension, which is why they're being rejected. Maybe I'm on the wrong track though, I admittedly really don't have much of an understanding of how our frontend fits together. A lot of folks on the Internet seem to be running into trouble when trying to get Typescript projects running with ESM, it all feels very experimental to me. One solution might be to separate the frontend in a separate CommonJS module with its own package.json, but that feels clunky. Help welcome!

As a side note, I'd like to highlight nodejs/node#49441. This issue is annoying for our service classes and service tests, as they are all loaded dynamically. Basically, any syntax error in any of them will be caught by ESM loader, but you'll have no clue where the error is. ESLint was not clever enough to catch all the syntax errors either, the only reliable way I found to help me out was to get the ESM loader to tell me there was some error and then run Prettier in check mode... Whilst this issue is painful when migrating hundreds of files in one go, I suspect it won't be too much of a bother when we're modifying a few files in a normal PR.

@PyvesB PyvesB added core Server, BaseService, GitHub auth, Shared helpers blocker PRs and epics which block other work labels Jun 20, 2021
@shields-ci
Copy link

shields-ci commented Jun 20, 2021

Warnings
⚠️ Lots 'o changes. Skipping diff-based checks.
Messages
📖

Thanks for contributing to our documentation. We ❤️ our documentarians!

📖 ✨ Thanks for your contribution to Shields, @PyvesB!

Generated by 🚫 dangerJS against bae618b

@lgtm-com
Copy link

lgtm-com bot commented Jun 20, 2021

This pull request introduces 1 alert when merging 3fb195c into 8f58817 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@lgtm-com
Copy link

lgtm-com bot commented Jun 20, 2021

This pull request introduces 1 alert when merging c461cb1 into 8f58817 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@lgtm-com
Copy link

lgtm-com bot commented Jun 20, 2021

This pull request introduces 1 alert when merging 4b23b29 into 8f58817 - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@PyvesB
Copy link
Member Author

PyvesB commented Jun 20, 2021

We'll probably need to land #6365 first: ci/circleci: main and ci/circleci: services are failing on Node 12 due to syntax errors, whereas their Node 14 counterparts seem fine.

The LGTM alert should go away once merged.

@PyvesB
Copy link
Member Author

PyvesB commented Jul 7, 2021

To the best of my knowledge, this is now functional and is ready for review! 🍾

@PyvesB PyvesB marked this pull request as ready for review July 7, 2021 07:46
@paulmelnikow
Copy link
Member

Hey @PyvesB, thanks for continuing to push this massive rock up the hill! Glad you've reached the top 🙌🏼

I've read a few of discussions about extensions in imports (including this one). I've not gone nearly as deeply down the rabbit hole as you have, though did have one question: could we avoid the explicit .js in all the import statements by renaming our files from .js to .mjs?

In general, I do think it is okay to merge this when it's working, and refine it later, as it's such a bear of a PR, though if we were to rename all the files, think that probably ought to happen before merging.

Copy link
Member

@paulmelnikow paulmelnikow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've not read every service file, as once you get past ~ docsrs, the diffs are no longer rendered without clicking each file, but I tried to spot-checked the non-service files. When this is up to date with main, I'd be willing to give this another read locally since it'll let me page through the diff more easily. (I could also do that now if I knew which commit in main to compare to, though I tried and couldn't easily work out which one that is.

core/badge-urls/make-badge-url.js Show resolved Hide resolved
core/badge-urls/make-badge-url.js Show resolved Hide resolved
doc/TUTORIAL.md Show resolved Hide resolved
frontend/package.json Show resolved Hide resolved
server.js Show resolved Hide resolved
.gitignore Outdated Show resolved Hide resolved
.prettierignore Show resolved Hide resolved
Copy link
Member

@chris48s chris48s left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approached this with a list of things you might have forgotten or overlooked and you've thought of all of them. Beyond that I've had a good read over this and done some testing locally and on staging. I have one request for additional docs which shouldn't block the merge but would be useful to get done this side of your break if poss, but I don't have any requests for changes.
I think once Paul's comments are addressed (which don't look major) I'm on board with this 👍

doc/TUTORIAL.md Show resolved Hide resolved
@@ -0,0 +1,32 @@
{
"name": "badge-frontend",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a blocker for merging this PR, but..

This is a workaround we will probably be stuck with for a while, but presumably at some point down the line we will be able to migrate the frontend from CommonJS to ESM too and then we can remove this.

I think it would be really useful to have an issue with a quick summary of

  • How far did you get
  • What problems did you encounter
  • What are the blockers (is gatsby core the only package we know of with a problem, or do we know of other packages in the frontend tree that would also need an update to unblock us - was tsnode one?)
  • If/when we can migrate the frontend to ESM:
    • What hacks can we remove?
    • Roughly what does that process look like?

Even if it is not 100% clear, I guess there is an extent to which that information currently exists in your head (or at least you have a clearer picture of this than anyone else) and it will be useful info at some point in future.

More broadly, I am so relieved you managed to find a way to avoid splitting the dependency tree in two 😌

Copy link
Member Author

@PyvesB PyvesB Jul 8, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, will prepare a little issue with some of the stuff in my head before I head off on holidays. :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we go: #6717

@PyvesB PyvesB temporarily deployed to shields-staging-pr-6651 July 8, 2021 18:20 Inactive
@lgtm-com
Copy link

lgtm-com bot commented Jul 8, 2021

This pull request introduces 1 alert when merging 9697ac1 into 23678fe - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@PyvesB
Copy link
Member Author

PyvesB commented Jul 8, 2021

I've read a few of discussions about extensions in imports (including this one). I've not gone nearly as deeply down the rabbit hole as you have, though did have one question: could we avoid the explicit .js in all the import statements by renaming our files from .js to .mjs?

The Node.js documentation does state the following:

A file extension must be provided when using the import keyword to resolve relative or absolute specifiers. Directory indexes (e.g. './startup/index.js') must also be fully specified.

There is an experimental feature that allows automatic resolution of extensions, and I believe that's one of the things being talked about in the issue you linked, but if it isn't considered stable, I would not be keen on using it at this stage. :)

@paulmelnikow
Copy link
Member

There is an experimental feature that allows automatic resolution of extensions, and I believe that's one of the things being talked about in the issue you linked, but if it isn't considered stable, I would not be keen on using it at this stage. :)

I am completely baffled that this "explicit" extension behavior is where Node has landed by default, and can't imagine this is going to be a popular option. Personally, I wouldn't mind using --experimental-specifier-resolution=node for a few months (since I think this will probably shake out) but I'm also okay with leaving the explicit extensions for now.

(It's clear that "type": "module" can be used in place of .mjs extensions.)

PyvesB and others added 2 commits July 8, 2021 21:27
Co-authored-by: Paul Melnikow <github@paulmelnikow.com>
@PyvesB PyvesB had a problem deploying to shields-staging-pr-6651 July 8, 2021 20:27 Failure
@lgtm-com
Copy link

lgtm-com bot commented Jul 8, 2021

This pull request introduces 1 alert when merging b4660d4 into 23678fe - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@PyvesB PyvesB temporarily deployed to shields-staging-pr-6651 July 8, 2021 20:33 Inactive
@lgtm-com
Copy link

lgtm-com bot commented Jul 8, 2021

This pull request introduces 1 alert when merging 813cbc3 into 23678fe - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

paulmelnikow
paulmelnikow previously approved these changes Jul 8, 2021
@PyvesB PyvesB changed the title Migrate from CommonJS to ESM, run [*****] Migrate from CommonJS to ESM Jul 9, 2021
@PyvesB
Copy link
Member Author

PyvesB commented Jul 9, 2021

@paulmelnikow I pushed a last commit: we're no longer using require-hacker and I had forgotten to remove it from the dependencies. :)

@lgtm-com
Copy link

lgtm-com bot commented Jul 9, 2021

This pull request introduces 1 alert when merging bae618b into 23678fe - view on LGTM.com

new alerts:

  • 1 for Unused variable, import, function or class

@PyvesB PyvesB merged commit 23c0406 into badges:master Jul 9, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocker PRs and epics which block other work core Server, BaseService, GitHub auth, Shared helpers
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Change server module to ESM from CommonJS
6 participants