Skip to content

Commit

Permalink
feat(eslint): rename eslint.config.js to eslint.config.cjs to resolve…
Browse files Browse the repository at this point in the history
… them as CommonJS (#29334)

This PR updates our generators to use `eslint.config.cjs` instead of
`eslint.config.js` so that Node resolution will treat it as CommonJS.
This solves an issue where having `"type": "module"` in `package.json`
will result in an error when Node tries to resolve the config file as
ESM.

Also allows us to clean up out Remix generators to not have to rename to
`eslint.config.cjs` to solve the same issue.

<!-- If this is a particularly complex change or feature addition, you
can request a dedicated Nx release for this pull request branch. Mention
someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they
will confirm if the PR warrants its own release for testing purposes,
and generate it for you if appropriate. -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->

## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
  • Loading branch information
jaysoo authored and ndcunningham committed Dec 20, 2024
1 parent 8f4eb15 commit 5c85c0d
Show file tree
Hide file tree
Showing 58 changed files with 774 additions and 336 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Sometimes we intentionally want to add or remove a dependency from our `package.
"checkObsoleteDependencies": true, // toggle to disable
"checkVersionMismatches": true, // toggle to disable
"ignoredDependencies": ["lodash"], // these libs will be omitted from checks
"ignoredFiles": ["webpack.config.js", "eslint.config.js"], // list of files that should be skipped for check
"ignoredFiles": ["webpack.config.js", "eslint.config.cjs"], // list of files that should be skipped for check
"includeTransitiveDependencies": true, // collect dependencies transitively from children
"useLocalPathsForWorkspaceDependencies": true // toggle to disable
}
Expand Down
2 changes: 1 addition & 1 deletion docs/generated/packages/eslint/executors/lint.json
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
"default": true
}
},
"examplesFile": "Linter can be configured in multiple ways. The basic way is to provide only `lintFilePatterns`, which is a mandatory property. This tells us where to look for files to lint.\n\n`project.json`:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"]\n }\n}\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Fixing linter issues\" %}\n\nLinter provides an automated way of fixing known issues. To ensure that those changes are properly cached, we need to add an `outputs` property to the `lint` target. Omitting the `outputs` property would produce an invalid cache record. Both of these properties are set by default when scaffolding a new project.\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"]\n }\n}\n```\n\nWith these settings, we can run the command with a `--fix` flag:\n\n```bash\nnx run frontend:lint --fix\n```\n\nWe can also set this flag via project configuration to always fix files when running lint:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"fix\": true\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Custom output format\" %}\n\nESLint executor uses the `stylish` output format by default. You can change this by specifying the `format` property:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"format\": \"compact\"\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Silence warnings\" %}\n\nMigrated or legacy projects tend to have an overwhelming amount of lint errors. We might want to change those temporarily to be warnings so they don't block the development. But they would still clutter the report. We can run the command with `--quiet` to hide warning (errors would still break the lint):\n\n```bash\nnx run frontend:lint --quiet\n```\n\nWe can also set this via project configuration as a default option.\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"quiet\": true\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Flat Config file\" %}\n\n`ESLint` provides several ways of specifying the configuration. The default one is using `.eslintrc.json` but you can override it by setting the `eslintConfig` flag. The new `Flat Config` is now also supported:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"eslintConfig\": \"eslint.config.js\"\n }\n}\n```\n\n**Note:** In contrast to other configuration formats, the `Flat Config` requires that all configuration files are converted to `eslint.config.js`. Built-in migrations and generators support only `.eslintrc.json` at the moment.\n\n{% /tab %}\n{% /tabs %}\n\n---\n",
"examplesFile": "Linter can be configured in multiple ways. The basic way is to provide only `lintFilePatterns`, which is a mandatory property. This tells us where to look for files to lint.\n\n`project.json`:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"]\n }\n}\n```\n\n## Examples\n\n{% tabs %}\n{% tab label=\"Fixing linter issues\" %}\n\nLinter provides an automated way of fixing known issues. To ensure that those changes are properly cached, we need to add an `outputs` property to the `lint` target. Omitting the `outputs` property would produce an invalid cache record. Both of these properties are set by default when scaffolding a new project.\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"]\n }\n}\n```\n\nWith these settings, we can run the command with a `--fix` flag:\n\n```bash\nnx run frontend:lint --fix\n```\n\nWe can also set this flag via project configuration to always fix files when running lint:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"fix\": true\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Custom output format\" %}\n\nESLint executor uses the `stylish` output format by default. You can change this by specifying the `format` property:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"format\": \"compact\"\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Silence warnings\" %}\n\nMigrated or legacy projects tend to have an overwhelming amount of lint errors. We might want to change those temporarily to be warnings so they don't block the development. But they would still clutter the report. We can run the command with `--quiet` to hide warning (errors would still break the lint):\n\n```bash\nnx run frontend:lint --quiet\n```\n\nWe can also set this via project configuration as a default option.\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"quiet\": true\n }\n}\n```\n\n{% /tab %}\n{% tab label=\"Flat Config file\" %}\n\n`ESLint` provides several ways of specifying the configuration. The default one is using `.eslintrc.json` but you can override it by setting the `eslintConfig` flag. The new `Flat Config` is now also supported:\n\n```json\n\"lint\": {\n \"executor\": \"@nx/eslint:lint\",\n \"outputs\": [\"{options.outputFile}\"],\n \"options\": {\n \"lintFilePatterns\": [\"apps/frontend/**/*.ts\"],\n \"eslintConfig\": \"eslint.config.cjs\"\n }\n}\n```\n\n**Note:** In contrast to other configuration formats, the `Flat Config` requires that all configuration files are converted to `eslint.config.cjs`. Built-in migrations and generators support only `.eslintrc.json` at the moment.\n\n{% /tab %}\n{% /tabs %}\n\n---\n",
"presets": []
},
"hasher": "./src/executors/lint/hasher",
Expand Down
2 changes: 1 addition & 1 deletion docs/shared/packages/eslint/dependency-checks.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Sometimes we intentionally want to add or remove a dependency from our `package.
"checkObsoleteDependencies": true, // toggle to disable
"checkVersionMismatches": true, // toggle to disable
"ignoredDependencies": ["lodash"], // these libs will be omitted from checks
"ignoredFiles": ["webpack.config.js", "eslint.config.js"], // list of files that should be skipped for check
"ignoredFiles": ["webpack.config.js", "eslint.config.cjs"], // list of files that should be skipped for check
"includeTransitiveDependencies": true, // collect dependencies transitively from children
"useLocalPathsForWorkspaceDependencies": true // toggle to disable
}
Expand Down
4 changes: 2 additions & 2 deletions docs/shared/recipes/tips-n-tricks/migrating-to-flat-eslint.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ See below a direct comparison between `JSON`, `JS` and `Flat` config:
{% tabs %}
{% tab label="Flat" %}

```js {% fileName="eslint.config.js" %}
```js {% fileName="eslint.config.cjs" %}
// the older versions were magically interpreting all the imports
// in flat config we do it explicitly
const nxPlugin = require('@nx/eslint-plugin');
const js = require('@eslint/js');
const baseConfig = require('./eslint.base.config.js');
const baseConfig = require('./eslint.base.config.cjs');
const globals = require('globals');
const jsoncParser = require('jsonc-eslint-parser');
const tsParser = require('@typescript-eslint/parser');
Expand Down
2 changes: 1 addition & 1 deletion e2e/angular/src/misc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ describe('Move Angular Project', () => {
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.app.json`);
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.json`);
expect(moveOutput).toContain(`CREATE ${newPath}/tsconfig.spec.json`);
expect(moveOutput).toContain(`CREATE ${newPath}/eslint.config.js`);
expect(moveOutput).toContain(`CREATE ${newPath}/eslint.config.cjs`);
expect(moveOutput).toContain(`CREATE ${newPath}/public/favicon.ico`);
expect(moveOutput).toContain(`CREATE ${newPath}/src/index.html`);
expect(moveOutput).toContain(`CREATE ${newPath}/src/main.ts`);
Expand Down
4 changes: 2 additions & 2 deletions e2e/angular/src/projects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,13 @@ describe('Angular Projects', () => {

it('should lint correctly with eslint and handle external HTML files and inline templates', async () => {
// disable the prefer-standalone rule for app1 which is not standalone
let app1EslintConfig = readFile(`${app1}/eslint.config.js`);
let app1EslintConfig = readFile(`${app1}/eslint.config.cjs`);
app1EslintConfig = app1EslintConfig.replace(
`'@angular-eslint/directive-selector': [`,
`'@angular-eslint/prefer-standalone': 'off',
'@angular-eslint/directive-selector': [`
);
updateFile(`${app1}/eslint.config.js`, app1EslintConfig);
updateFile(`${app1}/eslint.config.cjs`, app1EslintConfig);

// check apps and lib pass linting for initial generated code
runCLI(`run-many --target lint --projects=${app1},${lib1} --parallel`);
Expand Down
24 changes: 12 additions & 12 deletions e2e/eslint/src/linter-legacy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,10 @@ describe('Linter (legacy)', () => {
env: { NX_ADD_PLUGINS: 'false' },
});
checkFilesExist(
'eslint.config.js',
`apps/${myapp}/eslint.config.js`,
`libs/${mylib}/eslint.config.js`,
`libs/${mylib2}/eslint.config.js`
'eslint.config.cjs',
`apps/${myapp}/eslint.config.cjs`,
`libs/${mylib}/eslint.config.cjs`,
`libs/${mylib2}/eslint.config.cjs`
);
checkFilesDoNotExist(
'.eslintrc.json',
Expand All @@ -164,12 +164,12 @@ describe('Linter (legacy)', () => {

// move eslint.config one step up
// to test the absence of the flat eslint config in the project root folder
renameFile(`libs/${mylib2}/eslint.config.js`, `libs/eslint.config.js`);
renameFile(`libs/${mylib2}/eslint.config.cjs`, `libs/eslint.config.cjs`);
updateFile(
`libs/eslint.config.js`,
readFile(`libs/eslint.config.js`).replace(
`../../eslint.config.js`,
`../eslint.config.js`
`libs/eslint.config.cjs`,
readFile(`libs/eslint.config.cjs`).replace(
`../../eslint.config.cjs`,
`../eslint.config.cjs`
)
);

Expand Down Expand Up @@ -202,9 +202,9 @@ describe('Linter (legacy)', () => {
env: { NX_ADD_PLUGINS: 'false' },
});
checkFilesExist(
'eslint.config.js',
`${mylib}/eslint.config.js`,
'eslint.base.config.js'
'eslint.config.cjs',
`${mylib}/eslint.config.cjs`,
'eslint.base.config.cjs'
);
checkFilesDoNotExist(
'.eslintrc.json',
Expand Down
4 changes: 2 additions & 2 deletions e2e/eslint/src/linter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,8 +615,8 @@ describe('Linter', () => {
runCLI(`generate @nx/js:lib ${jsLib} --linter eslint`);

checkFilesExist(
`${reactLib}/eslint.config.js`,
`${jsLib}/eslint.config.js`
`${reactLib}/eslint.config.cjs`,
`${jsLib}/eslint.config.cjs`
);
checkFilesDoNotExist(
`${reactLib}/.eslintrc.json`,
Expand Down
10 changes: 0 additions & 10 deletions e2e/js/src/js-packaging.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,16 +178,6 @@ describe('packaging libs', () => {
`libs/${swcEsmLib}/src/index.ts`,
`export * from './lib/${swcEsmLib}.js';`
);
// We also need to update the eslint config file extensions to be explicitly commonjs
// TODO: re-evaluate this once we support ESM eslint configs
renameFile(
`libs/${tscEsmLib}/eslint.config.js`,
`libs/${tscEsmLib}/eslint.config.cjs`
);
renameFile(
`libs/${swcEsmLib}/eslint.config.js`,
`libs/${swcEsmLib}/eslint.config.cjs`
);

// Add additional entry points for `exports` field
updateJson(join('libs', tscLib, 'project.json'), (json) => {
Expand Down
4 changes: 2 additions & 2 deletions e2e/nx/src/__snapshots__/extras.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ exports[`Extra Nx Misc Tests task graph inputs should correctly expand dependent
],
"lib-base-123": [
"libs/lib-base-123/README.md",
"libs/lib-base-123/eslint.config.js",
"libs/lib-base-123/eslint.config.cjs",
"libs/lib-base-123/jest.config.ts",
"libs/lib-base-123/package.json",
"libs/lib-base-123/project.json",
Expand All @@ -39,7 +39,7 @@ exports[`Extra Nx Misc Tests task graph inputs should correctly expand dependent
],
"lib-dependent-123": [
"libs/lib-dependent-123/README.md",
"libs/lib-dependent-123/eslint.config.js",
"libs/lib-dependent-123/eslint.config.cjs",
"libs/lib-dependent-123/jest.config.ts",
"libs/lib-dependent-123/package.json",
"libs/lib-dependent-123/project.json",
Expand Down
6 changes: 3 additions & 3 deletions packages/angular/src/generators/library/library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1204,14 +1204,14 @@ describe('lib', () => {
describe('--linter', () => {
describe('eslint', () => {
it('should add valid eslint JSON configuration which extends from Nx presets (flat config)', async () => {
tree.write('eslint.config.js', '');
tree.write('eslint.config.cjs', '');

await runLibraryGeneratorWithOpts({ linter: Linter.EsLint });

const eslintConfig = tree.read('my-lib/eslint.config.js', 'utf-8');
const eslintConfig = tree.read('my-lib/eslint.config.cjs', 'utf-8');
expect(eslintConfig).toMatchInlineSnapshot(`
"const nx = require("@nx/eslint-plugin");
const baseConfig = require("../eslint.config.js");
const baseConfig = require("../eslint.config.cjs");
module.exports = [
...baseConfig,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ exports[`workspace move to nx layout should create nx.json 1`] = `
"!{projectRoot}/**/*.spec.[jt]s",
"!{projectRoot}/karma.conf.js",
"!{projectRoot}/.eslintrc.json",
"!{projectRoot}/eslint.config.js",
"!{projectRoot}/eslint.config.cjs",
],
"sharedGlobals": [],
},
Expand All @@ -104,7 +104,7 @@ exports[`workspace move to nx layout should create nx.json 1`] = `
"default",
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/.eslintignore",
"{workspaceRoot}/eslint.config.js",
"{workspaceRoot}/eslint.config.cjs",
],
},
"build": {
Expand All @@ -129,7 +129,7 @@ exports[`workspace move to nx layout should create nx.json 1`] = `
"inputs": [
"default",
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/eslint.config.js",
"{workspaceRoot}/eslint.config.cjs",
],
},
"test": {
Expand Down
7 changes: 5 additions & 2 deletions packages/angular/src/generators/ng-add/utilities/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ export function createNxJson(
]
: []),
...(targets.lint
? ['!{projectRoot}/.eslintrc.json', '!{projectRoot}/eslint.config.js']
? [
'!{projectRoot}/.eslintrc.json',
'!{projectRoot}/eslint.config.cjs',
]
: []),
].filter(Boolean),
},
Expand All @@ -85,7 +88,7 @@ export function createNxJson(
inputs: [
'default',
'{workspaceRoot}/.eslintrc.json',
'{workspaceRoot}/eslint.config.js',
'{workspaceRoot}/eslint.config.cjs',
],
cache: true,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@
<%_ if (jsx) { _%>"<%= offsetFromProjectRoot %>**/*.cy.jsx",<%_ } _%>
"<%= offsetFromProjectRoot %>**/*.d.ts"
],
"exclude": ["out-tsc", "test-output"<% if (linter === 'eslint') { %>, "eslint.config.js"<% } %>]
"exclude": ["out-tsc", "test-output"<% if (linter === 'eslint') { %>, "eslint.config.js", "eslint.config.cjs", "eslint.config.mjs"<% } %>]
}
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/flat-configs/javascript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const isPrettierAvailable =
*/
export default tseslint.config(
{
files: ['**/*.js', '**/*.jsx'],
files: ['**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs'],
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
},
{
Expand All @@ -40,7 +40,7 @@ export default tseslint.config(
plugins: { '@typescript-eslint': tseslint.plugin },
},
{
files: ['**/*.js', '**/*.jsx'],
files: ['**/*.js', '**/*.jsx', '**/*.cjs', '**/*.mjs'],
rules: {
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/flat-configs/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const isPrettierAvailable =
*/
export default tseslint.config(
{
files: ['**/*.ts', '**/*.tsx'],
files: ['**/*.ts', '**/*.tsx', '**/*.cts', '**/*.mts'],
extends: [eslint.configs.recommended, ...tseslint.configs.recommended],
},
{
Expand All @@ -30,7 +30,7 @@ export default tseslint.config(
},
},
{
files: ['**/*.ts', '**/*.tsx'],
files: ['**/*.ts', '**/*.tsx', , '**/*.cts', '**/*.mts'],
rules: {
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint/docs/eslint-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ We can also set this via project configuration as a default option.
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/frontend/**/*.ts"],
"eslintConfig": "eslint.config.js"
"eslintConfig": "eslint.config.cjs"
}
}
```

**Note:** In contrast to other configuration formats, the `Flat Config` requires that all configuration files are converted to `eslint.config.js`. Built-in migrations and generators support only `.eslintrc.json` at the moment.
**Note:** In contrast to other configuration formats, the `Flat Config` requires that all configuration files are converted to `eslint.config.cjs`. Built-in migrations and generators support only `.eslintrc.json` at the moment.

{% /tab %}
{% /tabs %}
Expand Down
5 changes: 5 additions & 0 deletions packages/eslint/migrations.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@
"version": "20.2.0-beta.5",
"description": "Update TypeScript ESLint packages to v8.13.0 if they are already on v8",
"implementation": "./src/migrations/update-20-2-0/update-typescript-eslint-v8-13-0"
},
"add-file-extensions-to-overrides": {
"version": "20.3.0-beta.1",
"description": "Update ESLint flat config to include .cjs, .mjs, .cts, and .mts files in overrides (if needed)",
"implementation": "./src/migrations/update-20-3-0/add-file-extensions-to-overrides"
}
},
"packageJsonUpdates": {
Expand Down
Loading

0 comments on commit 5c85c0d

Please sign in to comment.