@@ -60,7 +60,7 @@ or when referenced by `import` statements within ES module code:
60
60
* Strings passed in as an argument to ` --eval ` or ` --print ` , or piped to
61
61
` node ` via ` STDIN ` , with the flag ` --input-type=commonjs ` .
62
62
63
- ## <code >package.json</code > <code >"type"</code > field
63
+ ### <code >package.json</code > <code >"type"</code > field
64
64
65
65
Files ending with ` .js ` or ` .mjs ` , or lacking any extension,
66
66
will be loaded as ES modules when the nearest parent ` package.json ` file
@@ -97,7 +97,13 @@ if the nearest parent `package.json` contains `"type": "module"`.
97
97
import ' ./startup.js' ; // Loaded as ES module because of package.json
98
98
```
99
99
100
- ## Package Scope and File Extensions
100
+ Package authors should include the ` "type" ` field, even in packages where all
101
+ sources are CommonJS. Being explicit about the ` type ` of the package will
102
+ future-proof the package in case the default type of Node.js ever changes, and
103
+ it will also make things easier for build tools and loaders to determine how the
104
+ files in the package should be interpreted.
105
+
106
+ ### Package Scope and File Extensions
101
107
102
108
A folder containing a ` package.json ` file, and all subfolders below that
103
109
folder down until the next folder containing another ` package.json ` , is
@@ -156,7 +162,7 @@ package scope:
156
162
extension (since both ` .js ` and ` .cjs ` files are treated as CommonJS within a
157
163
` "commonjs" ` package scope).
158
164
159
- ## <code >--input-type</code > flag
165
+ ### <code >--input-type</code > flag
160
166
161
167
Strings passed in as an argument to ` --eval ` or ` --print ` (or ` -e ` or ` -p ` ), or
162
168
piped to ` node ` via ` STDIN ` , will be treated as ES modules when the
@@ -174,7 +180,9 @@ For completeness there is also `--input-type=commonjs`, for explicitly running
174
180
string input as CommonJS. This is the default behavior if ` --input-type ` is
175
181
unspecified.
176
182
177
- ## Package Entry Points
183
+ ## Packages
184
+
185
+ ### Package Entry Points
178
186
179
187
The ` package.json ` ` "main" ` field defines the entry point for a package,
180
188
whether the package is included into CommonJS via ` require ` or into an ES
@@ -209,15 +217,50 @@ be interpreted as CommonJS.
209
217
210
218
The ` "main" ` field can point to exactly one file, regardless of whether the
211
219
package is referenced via ` require ` (in a CommonJS context) or ` import ` (in an
212
- ES module context). Package authors who want to publish a package to be used in
213
- both contexts can do so by setting ` "main" ` to point to the CommonJS entry point
214
- and informing the package’s users of the path to the ES module entry point. Such
215
- a package would be accessible like ` require('pkg') ` and `import
216
- 'pkg/module.mjs'` . Alternatively the package ` "main"` could point to the ES
217
- module entry point and legacy users could be informed of the CommonJS entry
218
- point path, e.g. ` require('pkg/commonjs') ` .
219
-
220
- ## Package Exports
220
+ ES module context).
221
+
222
+ #### Compatibility with CommonJS-Only Versions of Node.js
223
+
224
+ Prior to the introduction of support for ES modules in Node.js, it was a common
225
+ pattern for package authors to include both CommonJS and ES module JavaScript
226
+ sources in their package, with ` package.json ` ` "main" ` specifying the CommonJS
227
+ entry point and ` package.json ` ` "module" ` specifying the ES module entry point.
228
+ This enabled Node.js to run the CommonJS entry point while build tools such as
229
+ bundlers used the ES module entry point, since Node.js ignored (and still
230
+ ignores) ` "module" ` .
231
+
232
+ Node.js can now run ES module entry points, but it remains impossible for a
233
+ package to define separate CommonJS and ES module entry points. This is for good
234
+ reason: the ` pkg ` variable created from ` import pkg from 'pkg' ` is not the same
235
+ singleton as the ` pkg ` variable created from ` const pkg = require('pkg') ` , so if
236
+ both are referenced within the same app (including dependencies), unexpected
237
+ behavior might occur.
238
+
239
+ There are two general approaches to addressing this limitation while still
240
+ publishing a package that contains both CommonJS and ES module sources:
241
+
242
+ 1 . Document a new ES module entry point that’s not the package ` "main" ` , e.g.
243
+ ` import pkg from 'pkg/module.mjs' ` (or ` import 'pkg/esm' ` , if using [ package
244
+ exports] [ ] ). The package ` "main" ` would still point to a CommonJS file, and
245
+ thus the package would remain compatible with older versions of Node.js that
246
+ lack support for ES modules.
247
+
248
+ 1 . Switch the package ` "main" ` entry point to an ES module file as part of a
249
+ breaking change version bump. This version and above would only be usable on
250
+ ES module-supporting versions of Node.js. If the package still contains a
251
+ CommonJS version, it would be accessible via a path within the package, e.g.
252
+ ` require('pkg/commonjs') ` ; this is essentially the inverse of the previous
253
+ approach. Package consumers who are using CommonJS-only versions of Node.js
254
+ would need to update their code from ` require('pkg') ` to e.g.
255
+ ` require('pkg/commonjs') ` .
256
+
257
+ Of course, a package could also include only CommonJS or only ES module sources.
258
+ An existing package could make a semver major bump to an ES module-only version,
259
+ that would only be supported in ES module-supporting versions of Node.js (and
260
+ other runtimes). New packages could be published containing only ES module
261
+ sources, and would be compatible only with ES module-supporting runtimes.
262
+
263
+ ### Package Exports
221
264
222
265
By default, all subpaths from a package can be imported (` import 'pkg/x.js' ` ).
223
266
Custom subpath aliasing and encapsulation can be provided through the
@@ -930,5 +973,6 @@ success!
930
973
[` import ` ]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
931
974
[` module .createRequire ()` ]: modules.html#modules_module_createrequire_filename
932
975
[dynamic instantiate hook]: #esm_dynamic_instantiate_hook
976
+ [package exports]: #esm_package_exports
933
977
[special scheme]: https://url.spec.whatwg.org/#special-scheme
934
978
[the official standard format]: https://tc39.github.io/ecma262/#sec-modules
0 commit comments