Migrate frontend to ESM
This is related to #6651, in particular https://github.com/badges/shields/pull/6651#discussion_r666389443.
Problem
Gatsby does not support ESM. See https://github.com/gatsbyjs/gatsby/issues/23705 and linked discussions for more information.
In particular, when running npm start midway through migrating the whole code to ESM, I was getting errors similar to the following:
[frontend] TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension "" for C:...\workspace\shields.cache\tmp-5248-0orlJ0tI72FY
npm run build was also producing different kinds of errors.
Current workaround
The solution was to break the frontend down into a separate module with its own frontend/package.json. Unlike Shields' top-level package.json, frontend/package.json does not contain the mention "type": "module", in other words it is still a CommonJS module.
In addition to mandating the extra frontend/package.json, the solution has the following caveats:
- the Babel configuration must be specified in
frontend/package.json. - the
gatsbydependency must be specified in bothpackage.jsonandfrontend/package.json, Gatsby will otherwise complain that the frontend package is not a Gatsby project. - the
startandbuildscripts frompackage.jsonhave an extracd frontendstep so that Gatsby is run fromfrontend/package.json. - in line with the directory where Gatsby is now run,
gatsby-browser.js,gatsby-config.jsandgatsby-node.jshave been moved to thefrontenddirectory. - the
supported-features.jsonandservice-definitions.ymlfiles are now produced in thefrontenddirectory. This is only a minor detail to make relative paths simpler. - the result of the
buildscript, i.e. thepublicfolder, is moved up one level back into the project's root. Gatsby producespublicin thefrontenddirectory where it's run and that can't be changed (https://github.com/gatsbyjs/gatsby/discussions/1878), and Heroku expectspublicto be in the project's root and that can't be changed ( https://github.com/heroku/heroku-buildpack-nodejs/issues/385). Additionally, our Cypress end-to-end setup will expectpublicto be in the root as well. - the
require-hackerdependency and themocha-ignore-pngs.jsfile were removed, as not compatible with ESM. These probably aren't needed anymore, as the ESM loader ignores PNGs anyway if my understanding is correct. - the
importstatements inmake-badge-url.jsmust be carefully tested, as they are used both by the ESM loader and Typescript loader, which have slightly different behaviours. For example,import { URL } from 'url'won't work there.
Future work
Once Gatsby becomes compatible with ESM, we would simply need to revert all aforementioned workarounds (apart from the require-hacker one), and potentially convert gatsby-browser.js, gatsby-config.js and gatsby-node.js to ESM formats as well. Additionally, it is my understanding that we will need to add js file extensions to the existing relative imports in the frontend code.
This issue is kind of still relevant but has changed substantially.
Now that we are off of Gatsby, all the detail above has changed, but having migrated to Docusaurus, we do still have some CommonJS frontend code (but a lot less). See https://github.com/badges/shields/pull/9014#discussion_r1142330196
The relevant upstream issues are now:
- https://github.com/facebook/docusaurus/issues/6520
- https://github.com/facebook/docusaurus/issues/5379