You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As part of our work for v36, we investigated moving over to an ESM-only package for @primer/react. This work was tackled over in: #3410
After the switch to "type": "module" in the project's package.json, we noticed several issues when working with our internal Next.js example and with other package's in the ecosystem. This issue will detail some of the challenges that we ran into and what work should be completed before we attempt this migration in the future.
Background
When authoring JavaScript using modules, the semantics of how a module is loaded depends on the runtime or bundler used. The syntax for modules themselves has also changed over the years, most recently going from CommonJS to ESM. To better support moving between these two formats, tools like Webpack and TypeScript introduced functionality to interop between these two worlds.
In Node.js v16+, the behavior when importing a .js file depends on the nearest package.json file. If this file contains "type": "module" then modules will by default load as ESM. Otherwise, the file will be treated as CommonJS. You can opt out of this default behavior by explicitly using an .mjs extension for ESM or .cjs for CommonJS.
When you import from a package, the corresponding tool or runtime (such as Webpack, TypeScript, esbuild, or Node.js) will look in the package's package.json to understand the entrypoints of the package. These can be defined in a number of fields, including main, exports, and module.
Note
The module type is not officially supported by Node.js but has been used by bundlers in the past to indicate an ESM only entrypoint
The semantics of how a module is loaded using one of these fields depends on the type from the package.json, either "type": "module" for ESM or CommonJS by default.
Challenges
The core behavioral difference is that when we use "type": "module" in our package.json then projects that use Webpack, like Next.js, by default use Node.js semantics for loading the package. This leads to a number of challenges:
Not all packages use "type": "module" and instead use "module" to provide an ESM bundle
Packages may use an "exports" field with an "import" condition but this will not work if the package.json is not ESM or the field does not use an .mjs extension
For the latter challenge, this occurs even when a project uses the following convention:
Despite the fact that it uses the import condition, importing the index.esm.js file will instead load with CommonJS semantics because the file uses a .js extension. This occurs because the root package.json does not specific "type": "module" and so files with the .js extension load with CommonJS by default. To work around this problem, the file should instead end with .mjsor the root package.json file should specify "type": "module" and use .cjs with the require condition.
Checklist
Update the following packages to support ESM when imported through Node.js
@primer/primitives
@primer/behaviors
@primer/octicons-react
Verify that packages that the project depend on correctly support ESM when imported through Node.js
The text was updated successfully, but these errors were encountered:
Hi! This issue has been marked as stale because it has been open with no activity for 180 days. You can comment on the issue or remove the stale label to keep it open. If you do nothing, this issue will be closed in 7 days.
Hi! This issue has been marked as stale because it has been open with no activity for 180 days. You can comment on the issue or remove the stale label to keep it open. If you do nothing, this issue will be closed in 7 days.
As part of our work for v36, we investigated moving over to an ESM-only package for
@primer/react
. This work was tackled over in: #3410After the switch to
"type": "module"
in the project'spackage.json
, we noticed several issues when working with our internal Next.js example and with other package's in the ecosystem. This issue will detail some of the challenges that we ran into and what work should be completed before we attempt this migration in the future.Background
When authoring JavaScript using modules, the semantics of how a module is loaded depends on the runtime or bundler used. The syntax for modules themselves has also changed over the years, most recently going from CommonJS to ESM. To better support moving between these two formats, tools like Webpack and TypeScript introduced functionality to interop between these two worlds.
In Node.js v16+, the behavior when importing a
.js
file depends on the nearestpackage.json
file. If this file contains"type": "module"
then modules will by default load as ESM. Otherwise, the file will be treated as CommonJS. You can opt out of this default behavior by explicitly using an.mjs
extension for ESM or.cjs
for CommonJS.When you import from a package, the corresponding tool or runtime (such as Webpack, TypeScript, esbuild, or Node.js) will look in the package's
package.json
to understand the entrypoints of the package. These can be defined in a number of fields, includingmain
,exports
, andmodule
.The semantics of how a module is loaded using one of these fields depends on the type from the
package.json
, either"type": "module"
for ESM or CommonJS by default.Challenges
The core behavioral difference is that when we use
"type": "module"
in our package.json then projects that use Webpack, like Next.js, by default use Node.js semantics for loading the package. This leads to a number of challenges:"type": "module"
and instead use"module"
to provide an ESM bundle"exports"
field with an "import" condition but this will not work if thepackage.json
is not ESM or the field does not use an.mjs
extensionFor the latter challenge, this occurs even when a project uses the following convention:
Despite the fact that it uses the
import
condition, importing theindex.esm.js
file will instead load with CommonJS semantics because the file uses a.js
extension. This occurs because the rootpackage.json
does not specific"type": "module"
and so files with the.js
extension load with CommonJS by default. To work around this problem, the file should instead end with.mjs
or the rootpackage.json
file should specify"type": "module"
and use.cjs
with therequire
condition.Checklist
@primer/primitives
@primer/behaviors
@primer/octicons-react
The text was updated successfully, but these errors were encountered: