@@ -945,7 +945,62 @@ $ node other.js
945945
946946## Dual CommonJS/ES module packages
947947
948- See [ the package examples repository] [ ] for details.
948+ Prior to the introduction of [ ` "exports" ` ] [ ] , authors of packages that support
949+ both CommonJS and ES modules typically used the ` "import" ` and ` "require" `
950+ conditions. However, using these conditions can lead to the _ dual package
951+ hazard_ , where the same package may be loaded twice (once as CommonJS and once
952+ as an ES module), causing issues with package state and object identity.
953+
954+ For example, given a package with the following ` package.json ` :
955+
956+ ``` json
957+ {
958+ "name" : " my-package" ,
959+ "exports" : {
960+ "import" : " ./index.mjs" ,
961+ "require" : " ./index.cjs"
962+ }
963+ }
964+ ```
965+
966+ If one dependency ` require() ` s ` my-package ` while another ` import ` s it, two
967+ separate copies of the package are loaded. Any state or objects exported by the
968+ package will not be shared between the two copies.
969+
970+ ### Approach 1: Use ` node ` and ` default ` conditions
971+
972+ The recommended approach to avoid the dual package hazard while still providing
973+ both CommonJS and ES module entry points is to use the ` "node" ` and ` "default" `
974+ conditions instead of ` "require" ` and ` "import" ` :
975+
976+ ``` json
977+ {
978+ "name" : " my-package" ,
979+ "exports" : {
980+ "node" : " ./index.cjs" ,
981+ "default" : " ./index.mjs"
982+ }
983+ }
984+ ```
985+
986+ With this configuration:
987+
988+ * Node.js always loads the CommonJS version, regardless of whether the package
989+ is ` require() ` d or ` import ` ed, avoiding the dual package hazard.
990+ * Other environments (such as browsers or bundlers configured for non-Node.js
991+ targets) use the ES module version via the ` "default" ` condition.
992+ * Bundlers configured to target Node.js use the ` "node" ` condition.
993+
994+ This approach ensures there is only one copy of the package loaded per
995+ environment, while still allowing non-Node.js environments to benefit from
996+ ES modules.
997+
998+ ### Approach 2: Isolate state in a CommonJS wrapper
999+
1000+ If the package must provide both true ESM and CJS entry points in Node.js (for
1001+ example, to allow ESM consumers to use top-level ` await ` ), the stateful parts
1002+ can be isolated in a CommonJS module that is shared by both entry points. See
1003+ [ the package examples repository] [ ] for details.
9491004
9501005## Node.js ` package.json ` field definitions
9511006
0 commit comments