From e224c3453dbbae1d36e3e165a73a71394b5002fe Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Sat, 5 Oct 2019 19:28:15 -0600 Subject: [PATCH 1/9] New: ES Module Compatibility --- designs/2019-esm-compatibilty/README.md | 222 ++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 designs/2019-esm-compatibilty/README.md diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md new file mode 100644 index 00000000..f9930089 --- /dev/null +++ b/designs/2019-esm-compatibilty/README.md @@ -0,0 +1,222 @@ +- Start Date: 2019-10-05 +- RFC PR: [#12321](https://github.com/eslint/eslint/pull/12321) +- Authors: Evan Plaice ([@evanplaice](https://github.com/evanplaice)) + +# ES Module Compatibility + +## Summary + +ES module support has been rolled out in all evergreen browsers and will soon land (unflagged) in node. Now is a good time to fill in the gaps to ensure ESLint users can effectively lint their ESM-based packages. + +## Motivation + +The new ES module standard is finally rolling out but, there already exists a massive ecosystem of packages build as CommonJS modules (incl ESLint). + +In the majority case, changing a package to be interpreted as an ES module by default is as simple as adding `"type": "module"` to `package.json`. + +In excepitonal edge cases it may require extra work to establish interoperability across package boundaries. The way ESLint uses `.js` config files is one of those edge cases. + +The goal of this RFC is to explore the different options for addressing this issue. + +## Detailed Design + +To understand the design outlined here requires some background info into the mechanics by which Node modules are loaded. + +### Jargon + +- Package - A NPM package (ie contains `package.json`) +- Module - A JS file +- CJS - A CommonJS module +- ESM - A Standard ECMAScript module +- Consumer - A package that uses/depends on this package +- Dependent - Package(s) that this package needs to work +- Boundary - The demarcation between package, consumer, dependent + +### A Crash Course on Package Boundaries + +Historically, NPM packages have come in a variety of different package formats (ie IIFE, AMD, UMD, CJS). Prior to an actual spec, NPM settled on CJS as it's de-facto module format. CJS isn't going anywhere, the addition of ESM is additive. + +By default, all NPM packages are CJS-based. That means all `.js` files will be read as CJS modules. To include an ES module in a CJS package, it must have the `.mjs` extension. + +In addition, if `package.json` contains `"type": "module"` then the package is ESM-based. Meaning, all `.js` files contained within will be treated as ESM. To include a CJS module in a ESM-based package, it must have the `.cjs` extension. + +This configuration option does *not* affect consumers or dependents. Their functionality depends entirely on their own configuration. Assuming all packages follow this rule, there should be no issues with interoperability between CJS/ESM. + +### The Scenario + +A user is creating a new package. They want it to be ESM for Browser <-> Node compatibility so they configure their package to be ESM-based. + +The user adds `eslint` as a devDependency, w/ a typical NPM script to lint the package contents. + +The user defines `eslint.config.js` outlining the ruleset they prefer to use within their package. + +### The Issue + +The user pacakge is ESM-based, all `.js` files within are read as ESM. + +ESLint is CJS-based, it loads all files within it's package boundary as CJS. + +The configuration file is defined as a CJS module (ie `module.exports`), but has the `.js` syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the configuration but the user has inadvertently signaled to Node that it uses the wrong module type. + +### The Fix + +Rename `eslint.config.js -> eslint.config.cjs` + +There is no documentation outlining how to define a ESM-based configuration. As such, it can be assumed that any JS-based ESLint config will always be a CJS module. + +Therefore, the `.cjs` extension needs to be assiciated w/ JS-based configrations. + +*/lib/cli-engine/config-array-factory.js* + +```diff +function loadConfigFile(filePath) { + switch (path.extname(filePath)) { + case ".js": ++ case ".cjs: + return loadJSConfigFile(filePath); + + case ".json": + if (path.basename(filePath) === "package.json") { + return loadPackageJSONConfigFile(filePath); + } + return loadJSONConfigFile(filePath); + + case ".yaml": + case ".yml": + return loadYAMLConfigFile(filePath); + + default: + return loadLegacyConfigFile(filePath); + } +} + +``` + +If a user: + +- is building a ESM-based package +- is using a JS-based configuration + +They should give the configuration a `.cjs` extension. + +## Documentation + +A quick mention in the [FAQ](https://github.com/eslint/eslint#frequently-asked-questions) should be suitable to document usage. + +## Drawbacks + +### Technical + +None. The change has no negative functionality or performance impacts. + +## People + +Some devs within the Node ecosystem are strongly opposed to supporting `"type": "module"` based packages at all. + +## Backwards Compatibility Analysis + +*tl;dr: Backward compatibility will be unaffected* + +### Story 1 - ESLint Compatibility + +This change is additive. It associates `.cjs` files with the existing Javascript configuration loader. + +The actual semantics of loading the CommonJS config do not change at all. The `.cjs` extension specifically exists as a escape hatch for this use case (ie loading a CommonJS file that exists in a ESM-based package). + +### Story 2 - Node Compatiblity + +ESM support rolls out (as a non-experimental feature) w/ Node 13. This includes: the ability to define a package as a ESM; and backward interoperability w/ CJS in ES modules by using the `.cjs` file extension. + +This change *only* impacts users who define their package as an ES module. Without Node 13+ that isn't possible. + +Existing packages that use the default (ie CommonJS) will be unaffected. + +## Alternatives + +### Alternative 1 - Suppress the error + +**[PR#12333](https://github.com/eslint/eslint/pull/12333)** + +There is some debate among the node/modules group surrounding whether the error that causes this issue should be removed altogether. + +The fencing exists to prevent users from creating dual-mode (ie both ESM/CJS) packages as interoperability between the two formats has issues. In the case of ESLint, loading a simple config file from a user-defined package should not cause any issues or side-effecs. + +Eating the exception is viable solution. Although, this may become dead code if the error is removed from Node's core. + +### Alternative 2 - Support dynamic `import()` + +Instead of using 'import-fresh' to require the config, import it in a cross-format-compatible way using dynamic `import()`. + +There has been and will continue to be a lot of talk about using this approach as the CJS/ESM interop story is fleshed out. + +For now it presents too many unknowns and -- even if it didn't -- adding `import()` to ESLint's core would force Node 13+ as a hard constraint. + +### Alternative 3: Deprecate JS-based configurations altogether + +This approach is controversial but this RFC would be incomplete w/o mentioning it. + +What is the benefit of supporting JS-based configurations at all? + +- JSON (w/ `strip-comments`) and YAML both support comments +- JS will load slower than it's context-free alternatives +- Do the config definitions really require a turing-complete syntax? +- Is the added complexity of supporting JS configs worth it? + +Benefits: + +- less complexity +- reduces ambiguity (ex CJS vs ESM) +- removes the `import-fresh` dependency + +Downsides + +- major breaking change w/ existing patterns +- JSON requires all strings to be quoted +- seriously, major breaking changes are not fun + +## Open Questions + + + +## Help Needed + + + +## Frequently Asked Questions + +> Why doesn't compatibility w/ ESM-based packages 'just work'? + +ESLint reaches across the package boundary to retrieve the user-defined configuration. If the consumer package is ESM-based, the `.js` config file will be seen as an ES module, and trying to `require()` it will throw an error. + +> What does this interop issue affect? + +Only ESM-based packages (ie `"type": "module"`). + +> What about 3rd-party linting tools that provide their own built-in ruleset for ESLint (ex [StandardJS](https://standardjs.com/))? + +They aren't impacted by this change. 3rd-party modules define both their code and the ESLint ruleset used within the same package boundary. + +## Related Discussions + +- [Transition Path Problems for Tooling - node/modules](https://github.com/nodejs/modules/issues/388) + + From 44cc3ad2ac375d7b92ac6f3d04d55f27e9d60697 Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Thu, 10 Oct 2019 16:57:59 -0600 Subject: [PATCH 2/9] Revision 1 - fix RFC ref - rewrite summary, less fluff more substance - use the correct config filenames - remove alternative 3 (NA) - add a ref to the issue that spawned this RFC --- designs/2019-esm-compatibilty/README.md | 41 +++++-------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index f9930089..8f3d2ef5 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -1,12 +1,14 @@ - Start Date: 2019-10-05 -- RFC PR: [#12321](https://github.com/eslint/eslint/pull/12321) +- RFC PR: [#43](https://github.com/eslint/rfcs/pull/43) - Authors: Evan Plaice ([@evanplaice](https://github.com/evanplaice)) # ES Module Compatibility ## Summary -ES module support has been rolled out in all evergreen browsers and will soon land (unflagged) in node. Now is a good time to fill in the gaps to ensure ESLint users can effectively lint their ESM-based packages. +ES module support is rolling out in the latest version of Node. One change included in that update is the ability to define a package as an ES module by default. That means all `.js` files will be evaluated as ES rather than CommonJS modules by default. + +This breakes the existing functionality for ESLint JS configs (ie which are CJS). The fix for this is to use the alternative `.cjs` extension to explicitly signal that the config file is a CommonJS module. This RFC addresses this issue and outlines the specifics required to add support for the `.cjs` extension. ## Motivation @@ -48,7 +50,7 @@ A user is creating a new package. They want it to be ESM for Browser <-> Node co The user adds `eslint` as a devDependency, w/ a typical NPM script to lint the package contents. -The user defines `eslint.config.js` outlining the ruleset they prefer to use within their package. +The user defines `.eslintrc.js` outlining the ruleset they prefer to use within their package. ### The Issue @@ -60,7 +62,7 @@ The configuration file is defined as a CJS module (ie `module.exports`), but has ### The Fix -Rename `eslint.config.js -> eslint.config.cjs` +Rename `.eslintrc.js -> .eslintrc.cjs` There is no documentation outlining how to define a ESM-based configuration. As such, it can be assumed that any JS-based ESLint config will always be a CJS module. @@ -151,29 +153,6 @@ There has been and will continue to be a lot of talk about using this approach a For now it presents too many unknowns and -- even if it didn't -- adding `import()` to ESLint's core would force Node 13+ as a hard constraint. -### Alternative 3: Deprecate JS-based configurations altogether - -This approach is controversial but this RFC would be incomplete w/o mentioning it. - -What is the benefit of supporting JS-based configurations at all? - -- JSON (w/ `strip-comments`) and YAML both support comments -- JS will load slower than it's context-free alternatives -- Do the config definitions really require a turing-complete syntax? -- Is the added complexity of supporting JS configs worth it? - -Benefits: - -- less complexity -- reduces ambiguity (ex CJS vs ESM) -- removes the `import-fresh` dependency - -Downsides - -- major breaking change w/ existing patterns -- JSON requires all strings to be quoted -- seriously, major breaking changes are not fun - ## Open Questions From 27f69f4667cc56656be6ad028681b6b65e821bc3 Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Tue, 15 Oct 2019 16:36:59 -0600 Subject: [PATCH 3/9] Revision 2 - fix nits and spelling errors - rewite the intro again for clarity - change future to present tense - rewrite 'Motivation' to be more concise - remove implementation specifics - add FAQ covering ESM-based configs - add reference to the implementation PR --- designs/2019-esm-compatibilty/README.md | 107 ++++++++++-------------- 1 file changed, 43 insertions(+), 64 deletions(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index 8f3d2ef5..deda7595 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -6,19 +6,21 @@ ## Summary -ES module support is rolling out in the latest version of Node. One change included in that update is the ability to define a package as an ES module by default. That means all `.js` files will be evaluated as ES rather than CommonJS modules by default. +**This Issue** -This breakes the existing functionality for ESLint JS configs (ie which are CJS). The fix for this is to use the alternative `.cjs` extension to explicitly signal that the config file is a CommonJS module. This RFC addresses this issue and outlines the specifics required to add support for the `.cjs` extension. +Node now supports ES modules. ESLint configurations that use the CommonJS format (i.e., `.eslintrc`, `.eslintrc.js`) are not compatible with ES module based packages. -## Motivation +**The Impact** + +This applies to ES module based packages (i.e., packages using `"type": "module"`) using a CommonJS configuration (i.e., `.eslintrc`, `.eslintrc.js`). -The new ES module standard is finally rolling out but, there already exists a massive ecosystem of packages build as CommonJS modules (incl ESLint). +**The Fix** -In the majority case, changing a package to be interpreted as an ES module by default is as simple as adding `"type": "module"` to `package.json`. +Node provides an 'escape hatch' via the `.cjs` extension. The extension explicitly signals to Node that the file should *always* evaluate as CommonJS. Support for the `.cjs` needs to be added to ESLint, and ESLint users building ES module based packages need to be notified. -In excepitonal edge cases it may require extra work to establish interoperability across package boundaries. The way ESLint uses `.js` config files is one of those edge cases. +## Motivation -The goal of this RFC is to explore the different options for addressing this issue. +ES modules are here. ESLint is ubiquitous in the JS ecosystem. With some minor adjustments, ESLint can be made to be compatible with the new format. ## Detailed Design @@ -26,73 +28,47 @@ To understand the design outlined here requires some background info into the me ### Jargon -- Package - A NPM package (ie contains `package.json`) +- Package - A NPM package (i.e., contains `package.json`) - Module - A JS file - CJS - A CommonJS module -- ESM - A Standard ECMAScript module +- ESM - A standard ECMAScript module - Consumer - A package that uses/depends on this package - Dependent - Package(s) that this package needs to work - Boundary - The demarcation between package, consumer, dependent ### A Crash Course on Package Boundaries -Historically, NPM packages have come in a variety of different package formats (ie IIFE, AMD, UMD, CJS). Prior to an actual spec, NPM settled on CJS as it's de-facto module format. CJS isn't going anywhere, the addition of ESM is additive. +Historically, NPM packages have come in a variety of different package formats (e.g., IIFE, AMD, UMD, CJS). Prior to an actual spec, NPM settled on CJS as it's de-facto module format. CJS isn't going anywhere, the addition of ESM is additive. By default, all NPM packages are CJS-based. That means all `.js` files will be read as CJS modules. To include an ES module in a CJS package, it must have the `.mjs` extension. -In addition, if `package.json` contains `"type": "module"` then the package is ESM-based. Meaning, all `.js` files contained within will be treated as ESM. To include a CJS module in a ESM-based package, it must have the `.cjs` extension. +If, `package.json` contains `"type": "module"` then the package is ESM-based. Meaning, all `.js` files contained within will be treated as ESM. To include a CJS module in a ESM-based package, it must have the `.cjs` extension. -This configuration option does *not* affect consumers or dependents. Their functionality depends entirely on their own configuration. Assuming all packages follow this rule, there should be no issues with interoperability between CJS/ESM. +This configuration option does *not* affect consumers or dependents. Whatever the configuration, it applies to all modules within the package boundary. Assuming packages only ever directly import within their package boundary, there should be no issues with interoperability between CJS/ESM. ### The Scenario -A user is creating a new package. They want it to be ESM for Browser <-> Node compatibility so they configure their package to be ESM-based. +A user is creating a new package. They prefer ESM for Browser <-> Node compatibility so they configure their package to be ESM-based. -The user adds `eslint` as a devDependency, w/ a typical NPM script to lint the package contents. +The user adds `eslint` as a devDependency and a typical NPM script to lint the package's contents. -The user defines `.eslintrc.js` outlining the ruleset they prefer to use within their package. +The user defines `.eslintrc.js` outlining the rule set they prefer to use within their package. ### The Issue -The user pacakge is ESM-based, all `.js` files within are read as ESM. +The user package is ESM-based, all `.js` files within are read as ESM. ESLint is CJS-based, it loads all files within it's package boundary as CJS. -The configuration file is defined as a CJS module (ie `module.exports`), but has the `.js` syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the configuration but the user has inadvertently signaled to Node that it uses the wrong module type. +The configuration file is defined as a CJS module (i.e., `module.exports`), but has a `.js` extension syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the user-defined configuration but the user has inadvertently signaled to Node to load it with the wrong module loader. ### The Fix -Rename `.eslintrc.js -> .eslintrc.cjs` - -There is no documentation outlining how to define a ESM-based configuration. As such, it can be assumed that any JS-based ESLint config will always be a CJS module. - -Therefore, the `.cjs` extension needs to be assiciated w/ JS-based configrations. - -*/lib/cli-engine/config-array-factory.js* +Add support for the `.cjs` file extension -```diff -function loadConfigFile(filePath) { - switch (path.extname(filePath)) { - case ".js": -+ case ".cjs: - return loadJSConfigFile(filePath); +*Note: In Node, `.cjs` will always load as a CommonJS module, irrespective of package configuration* - case ".json": - if (path.basename(filePath) === "package.json") { - return loadPackageJSONConfigFile(filePath); - } - return loadJSONConfigFile(filePath); - - case ".yaml": - case ".yml": - return loadYAMLConfigFile(filePath); - - default: - return loadLegacyConfigFile(filePath); - } -} - -``` +### Usage If a user: @@ -113,7 +89,7 @@ None. The change has no negative functionality or performance impacts. ## People -Some devs within the Node ecosystem are strongly opposed to supporting `"type": "module"` based packages at all. +Some developers within the Node ecosystem are strongly opposed to supporting `"type": "module"` at all. ## Backwards Compatibility Analysis @@ -121,17 +97,17 @@ Some devs within the Node ecosystem are strongly opposed to supporting `"type": ### Story 1 - ESLint Compatibility -This change is additive. It associates `.cjs` files with the existing Javascript configuration loader. +This change is additive. It associates `.cjs` files with JS configurations. -The actual semantics of loading the CommonJS config do not change at all. The `.cjs` extension specifically exists as a escape hatch for this use case (ie loading a CommonJS file that exists in a ESM-based package). +The existing semantics of loading CommonJS configurations for CommonJS-based packages do not change. -### Story 2 - Node Compatiblity +### Story 2 - Node Compatibility -ESM support rolls out (as a non-experimental feature) w/ Node 13. This includes: the ability to define a package as a ESM; and backward interoperability w/ CJS in ES modules by using the `.cjs` file extension. +In Node, ES module and `.cjs` support roll out together. -This change *only* impacts users who define their package as an ES module. Without Node 13+ that isn't possible. +This change *only* impacts users who define their package as an ES module. -Existing packages that use the default (ie CommonJS) will be unaffected. +Existing packages that use the default (i.e., CommonJS module resolution) will be unaffected. ## Alternatives @@ -139,19 +115,17 @@ Existing packages that use the default (ie CommonJS) will be unaffected. **[PR#12333](https://github.com/eslint/eslint/pull/12333)** -There is some debate among the node/modules group surrounding whether the error that causes this issue should be removed altogether. +The fencing exists to prevent users from creating dual-mode (i.e., both ESM/CJS) packages as interoperability between the two format can cause issues. In the case of ESLint, loading a simple config file from a user-defined package should not cause any issues or side-effects. -The fencing exists to prevent users from creating dual-mode (ie both ESM/CJS) packages as interoperability between the two formats has issues. In the case of ESLint, loading a simple config file from a user-defined package should not cause any issues or side-effecs. - -Eating the exception is viable solution. Although, this may become dead code if the error is removed from Node's core. +Eating the exception is viable solution. ### Alternative 2 - Support dynamic `import()` Instead of using 'import-fresh' to require the config, import it in a cross-format-compatible way using dynamic `import()`. -There has been and will continue to be a lot of talk about using this approach as the CJS/ESM interop story is fleshed out. +There has been and will continue to be a lot of talk about using this approach as the CJS/ESM interoperability story is fleshed out. -For now it presents too many unknowns and -- even if it didn't -- adding `import()` to ESLint's core would force Node 13+ as a hard constraint. +For now it presents too many unknowns. ## Open Questions @@ -179,17 +153,22 @@ For now it presents too many unknowns and -- even if it didn't -- adding `import > Why doesn't compatibility w/ ESM-based packages 'just work'? -ESLint reaches across the package boundary to retrieve the user-defined configuration. If the consumer package is ESM-based, the `.js` config file will be seen as an ES module, and trying to `require()` it will throw an error. +ESLint reaches across the package boundary to retrieve the user-defined configuration. If the consumer package is ESM-based, the `.js` config file will be seen as an ES module. When the ES module loader encounters `module.exports` (i.e., the CommonJS module specifier) it will throw an error. + +> What does this interoperability issue affect? + +Only ESM-based packages (i.e., packages with `"type": "module"` defined in package.json). -> What does this interop issue affect? +> What about 3rd-party linting tools that provide their own built-in rule set for ESLint (ex [StandardJS](https://standardjs.com/))? -Only ESM-based packages (ie `"type": "module"`). +They aren't impacted by this change. 3rd-party modules define both their code and the ESLint rule set used within the same package boundary. -> What about 3rd-party linting tools that provide their own built-in ruleset for ESLint (ex [StandardJS](https://standardjs.com/))? +> What about support for ES module configurations -They aren't impacted by this change. 3rd-party modules define both their code and the ESLint ruleset used within the same package boundary. +The scope of this RFC is limited to only ES module compatibility concerns. If there is a desire to add support for ESM-based configurations, it will need to be addressed in another RFC. ## Related Discussions - [Issue #12321](https://github.com/eslint/eslint/pull/12321) +- [PR #12321](https://github.com/eslint/eslint/pull/12321) - [Transition Path Problems for Tooling - node/modules](https://github.com/nodejs/modules/issues/388) From 028bbd83846c2c4e29d775fbefdd562c36a35684 Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Tue, 15 Oct 2019 22:48:09 -0600 Subject: [PATCH 4/9] Revision 3 - fix more nits - correct the name/link to the related issue --- designs/2019-esm-compatibilty/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index deda7595..b3ce17a3 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -56,9 +56,9 @@ The user defines `.eslintrc.js` outlining the rule set they prefer to use within ### The Issue -The user package is ESM-based, all `.js` files within are read as ESM. +When the user package is ESM-based, all `.js` files within are read as ESM. -ESLint is CJS-based, it loads all files within it's package boundary as CJS. +However, ESLint is CJS-based so, it loads all files within it's package boundary as CJS. The configuration file is defined as a CJS module (i.e., `module.exports`), but has a `.js` extension syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the user-defined configuration but the user has inadvertently signaled to Node to load it with the wrong module loader. @@ -87,7 +87,7 @@ A quick mention in the [FAQ](https://github.com/eslint/eslint#frequently-asked-q None. The change has no negative functionality or performance impacts. -## People +### People Some developers within the Node ecosystem are strongly opposed to supporting `"type": "module"` at all. @@ -169,6 +169,6 @@ The scope of this RFC is limited to only ES module compatibility concerns. If th ## Related Discussions -- [Issue #12321](https://github.com/eslint/eslint/pull/12321) +- [Issue #12319](https://github.com/eslint/eslint/issues/12319) - [PR #12321](https://github.com/eslint/eslint/pull/12321) - [Transition Path Problems for Tooling - node/modules](https://github.com/nodejs/modules/issues/388) From d8e3f120e555be3da5973b54703aad11a585888e Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Tue, 15 Oct 2019 22:52:24 -0600 Subject: [PATCH 5/9] Revision 4 - fix grammatical mistake --- designs/2019-esm-compatibilty/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index b3ce17a3..ac17655c 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -58,7 +58,7 @@ The user defines `.eslintrc.js` outlining the rule set they prefer to use within When the user package is ESM-based, all `.js` files within are read as ESM. -However, ESLint is CJS-based so, it loads all files within it's package boundary as CJS. +However, ESLint is CJS-based so, it loads all files within its package boundary as CJS. The configuration file is defined as a CJS module (i.e., `module.exports`), but has a `.js` extension syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the user-defined configuration but the user has inadvertently signaled to Node to load it with the wrong module loader. From 77eef25a3af0026335d809221d15f9e69180b7ca Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Fri, 25 Oct 2019 14:16:58 -0600 Subject: [PATCH 6/9] Revision 5 Mention configuration loader priority --- designs/2019-esm-compatibilty/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index ac17655c..3ee71237 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -77,6 +77,20 @@ If a user: They should give the configuration a `.cjs` extension. +### Priority + +With the addition of `.cjs`, the new priority for configuration files will be + +1. .eslintrc.cjs +2. .eslintrc.js +3. .eslintrc.yaml +4. .eslintrc.yml +5. .eslintrc.json +6. .eslintrc +7. package.json + +`.cjs` is placed higher than `.js` because -- unlike the latter -- `.cjs` does not allow for ambiguity. A `.cjs` file is always interpreted as CommonJS regardless of context. + ## Documentation A quick mention in the [FAQ](https://github.com/eslint/eslint#frequently-asked-questions) should be suitable to document usage. From 7ae77660a7ce15b80c891e5590ced8c750acbe2f Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Fri, 25 Oct 2019 16:51:57 -0600 Subject: [PATCH 7/9] Revision 6 --- designs/2019-esm-compatibilty/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index 3ee71237..393fffec 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -89,8 +89,6 @@ With the addition of `.cjs`, the new priority for configuration files will be 6. .eslintrc 7. package.json -`.cjs` is placed higher than `.js` because -- unlike the latter -- `.cjs` does not allow for ambiguity. A `.cjs` file is always interpreted as CommonJS regardless of context. - ## Documentation A quick mention in the [FAQ](https://github.com/eslint/eslint#frequently-asked-questions) should be suitable to document usage. From c762789209d10b8c26f7b038968bec0118092f2c Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Thu, 21 Nov 2019 20:59:08 -0700 Subject: [PATCH 8/9] Revision 7 Update 'Documentation' section with necessary documentation updates. --- designs/2019-esm-compatibilty/README.md | 29 ++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index 393fffec..6aba9c90 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -91,7 +91,34 @@ With the addition of `.cjs`, the new priority for configuration files will be ## Documentation -A quick mention in the [FAQ](https://github.com/eslint/eslint#frequently-asked-questions) should be suitable to document usage. +The [Configuration File Formats](https://github.com/eslint/website/blob/master/docs/6.0.0/user-guide/configuring.md#configuration-file-formats) section will need to be updated. + + +``` +## Configuration File Formats + +ESLint supports configuration files in several formats: + +* **JavaScript** - use `.eslintrc.js` and export an object containing your configuration. +* **JavaScript (ESM) - same as `.eslintrc.js but used with ES module packages <--- +* **YAML** - use `.eslintrc.yaml` or `.eslintrc.yml` to define the configuration structure. +* **JSON** - use `.eslintrc.json` to define the configuration structure. ESLint's JSON files also allow JavaScript-style comments. +* **Deprecated** - use `.eslintrc`, which can be either JSON or YAML. +* **package.json** - create an `eslintConfig` property in your `package.json` file and define your configuration there. + +If there are multiple configuration files in the same directory, ESLint will only use one. The priority order is: + +1. `.eslintrc.js` +1. `.eslintrc.cjs` <--- +1. `.eslintrc.yaml` +1. `.eslintrc.yml` +1. `.eslintrc.json` +1. `.eslintrc` +1. `package.json` + +**Note:** JavaScript (ESM) is for use with JavaScript packages that specify `"type":"module"` in `package.json`. <--- + +``` ## Drawbacks From df396ffa891012dad6908af36178d064e47f0bcb Mon Sep 17 00:00:00 2001 From: Evan Plaice Date: Fri, 22 Nov 2019 01:44:27 -0700 Subject: [PATCH 9/9] Revision 8 --- designs/2019-esm-compatibilty/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/designs/2019-esm-compatibilty/README.md b/designs/2019-esm-compatibilty/README.md index 6aba9c90..ebde0522 100644 --- a/designs/2019-esm-compatibilty/README.md +++ b/designs/2019-esm-compatibilty/README.md @@ -81,19 +81,18 @@ They should give the configuration a `.cjs` extension. With the addition of `.cjs`, the new priority for configuration files will be +1. .eslintrc.js 1. .eslintrc.cjs -2. .eslintrc.js -3. .eslintrc.yaml -4. .eslintrc.yml -5. .eslintrc.json -6. .eslintrc -7. package.json +1. .eslintrc.yaml +1. .eslintrc.yml +1. .eslintrc.json +1. .eslintrc +1. package.json ## Documentation The [Configuration File Formats](https://github.com/eslint/website/blob/master/docs/6.0.0/user-guide/configuring.md#configuration-file-formats) section will need to be updated. - ``` ## Configuration File Formats