Prerequisites
- Node.js 12 is recommended for Nx 11.
- The guide assumes Nx CLI version 11.x is installed globally.
- Having Angular CLI version 11.x installed globally is also advisable.
Setting up a new Nx Angular workspace with angular-eslint
When starting fresh, you have two workspace presets to choose from: empty or angular. Both paths lead to a fully functional Nx workspace with Angular and ESLint integrated.
Option 1: Use the empty workspace preset
The empty preset generates a workspace.json file at version 2, which aligns with Nx plugins built for Nx 11 and beyond.
-
Create a new workspace.
Begin by scaffolding a minimal Nx workspace.With NPM CLI:
npm init nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=empty --no-nx-cloud --package-manager=npmWith PNPM CLI:
pnpm init nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=empty --no-nx-cloud --package-manager=pnpmWith Yarn CLI:
yarn create nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=empty --no-nx-cloud --package-manager=yarn -
Define the base branch for
affectedcommands.
In 2020, many Git repositories adoptedmainas the default branch. However, Nx version 11.0.18 still defaults to comparing againstmaster, irrespective of your Git configuration.If your default branch is
main:
npx json -I -f nx.json -e "this.affected.defaultBase = 'main';" -
Remove TSLint.
TSLint ships with every new Nx workspace, but it's now officially retired. Uninstall thetslintpackage.With NPM CLI:
npm uninstall tslintWith Yarn CLI:
yarn remove tslintAn alternative is to add a
preinstallscript that permanently purges Codelyzer and TSLint, even if generators attempt to reinstall them.With NPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(npm uninstall codelyzer || echo ✅ Codelyzer is already removed.) && (npm uninstall tslint || echo ✅ TSLint is already removed.)';" npm installWith PNPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(pnpm remove codelyzer || echo ✅ Codelyzer is already removed.) && (pnpm remove tslint || echo ✅ TSLint is already removed.)';" pnpm installWith Yarn CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(yarn remove codelyzer || echo ✅ Codelyzer is already removed.) && (yarn remove tslint || echo ✅ TSLint is already removed.)';" yarn install -
Install and configure the
@nrwl/angularpackage.
This package provides the generators and executors needed for Angular projects within Nx.With NPM CLI:
npm install @nrwl/angular nx generate @nrwl/angular:initWith PNPM CLI:
pnpm add @nrwl/angular nx generate @nrwl/angular:initWith Yarn CLI:
yarn add @nrwl/angular nx generate @nrwl/angular:init -
Activate Angular strict mode.
We advocate for strict TypeScript and Angular settings. Enable strict mode for both application and library projects.
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].strict = true;" npx json -I -f workspace.json -e "this.generators['@nrwl/angular:library'].strict = true;" -
Adopt ESLint as the default linter.
Set ESLint as the linter for all new Angular projects, which automatically adds the necessary angular-eslint plugins.
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].linter = 'eslint';" npx json -I -f workspace.json -e "this.generators['@nrwl/angular:library'].linter = 'eslint';" -
Choose a unit test runner.
Nx supports both Jest and Karma for Angular projects. Pick the one that suits your workflow.If using Jest:
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].unitTestRunner = 'jest';" npx json -I -f workspace.json -e "this.generators['@nrwl/angular:library'].unitTestRunner = 'jest';"If using Karma:
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].unitTestRunner = 'karma';" npx json -I -f workspace.json -e "this.generators['@nrwl/angular:library'].unitTestRunner = 'karma';" -
Choose an end-to-end test runner.
For e2e testing, Nx offers Cypress and Protractor for Angular applications.If using Cypress:
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].e2eTestRunner = 'cypress';"If using Protractor:
npx json -I -f workspace.json -e "this.generators['@nrwl/angular:application'].e2eTestRunner = 'protractor';" -
Generate an Angular application.
With the generators configured as above, your new application will come pre-configured with ESLint and angular-eslint.
nx generate @nrwl/angular:application --name=booking-app --prefix=booking --tags="type:app,scope:booking" --no-interactiveDon't forget to assign project tags to the generated e2e test project.
npx json -I -f nx.json -e "this.projects['booking-app-e2e'].tags = ['type:e2e','scope:booking'];" -
Set strict Angular build budgets.
As of Nx 11.0.18, build budgets don't automatically adapt to Angular strict mode. Apply the same thresholds used by Angular CLI 11 in strict mode.The main bundle should warn at 500 KB and error at 1 MB. Component styles should warn at 2 KB and error at 4 KB.
npx json -I -f workspace.json -e "this.projects['booking-app'].targets.build.configurations.production.budgets = [{ type: 'initial', maximumWarning: '500kb', maximumError: '1mb' }, { type: 'anyComponentStyle', maximumWarning: '2kb', maximumError: '4kb' }];" -
Remove Codelyzer.
Angular CLI 11 bundles Codelyzer by default. Since TSLint is now deprecated, it's time to part ways with this package as well.With NPM CLI:
npm uninstall codelyzerWith PNPM CLI:
pnpm remove codelyzerWith Yarn CLI:
yarn remove codelyzer -
Create a workspace library.
To test the setup for libraries, generate a shared Angular library within the workspace.
nx generate @nrwl/angular:library feature-flight-search --directory=booking --prefix=booking --tags="type:feature,scope:booking" --buildable --enable-ivy --no-interactiveLeverage Nx 11's improved incremental builds and computation caching by making the library buildable (though not publishable) and compiled with Ivy.
-
Run the linter.
Execute thelinttarget across all projects to confirm that ESLint and angular-eslint are functioning as expected.
nx run-many --target=lint --all
At this point, you have a new Nx workspace containing an Angular app and a shared library. The empty preset ensures you're on workspace configuration version 2, which introduces the terminology of executors, generators, and targets.
Inspect workspace.json to confirm that the lint targets are wired to the @nrwl/linter:eslint executor.
The root .eslintrc.json should reference the @nrwl/nx/typescript plugin. Check the project-level .eslintrc.json files in both the app and library to see the @nrwl/nx/angular, @nrwl/nx/angular-template, and @angular-eslint/template/process-inline-templates plugins listed.
Option 2: Apply the Angular workspace preset
Starting from Nx 11.0.18, the angular workspace preset scaffolds the initial application with angular-eslint included. However, the initial application and end-to-end test projects are generated without honoring any of these flags:
create-applicatione2e-test-runnerno-interactivestricttagsunit-test-runner
Additionally, the --linter flag is defective — it always responds with the same error message, no matter how it is used:
> NX ERROR Invalid linter
It must be one of the following:
eslint
tslint
Even so, ESLint with angular-eslint remains the default linter.
This forces us to remove the initial projects when the defaults are not acceptable. The process then involves adjusting the schematics configuration and recreating both the application and end-to-end test projects from scratch.
-
Start by creating an Nx Angular workspace.
Via the NPM CLI:
npm init nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --linter=eslint --no-nx-cloud --style=css --package-manager=npmVia the PNPM CLI:
pnpm init nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --linter=eslint --no-nx-cloud --style=css --package-manager=pnpmVia the Yarn CLI:
yarn create nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --linter=eslint --no-nx-cloud --style=css --package-manager=yarn -
Adjust the base branch for
affectedcommands.
If you adoptedmainas your default Git branch this year, note that Nx 11.0.18 still compares againstmasterby default, regardless of what Git uses as its default branch.If your default branch is
main:
npx json -I -f nx.json -e "this.affected.defaultBase = 'main';" -
Remove Codelyzer and TSLint.
Theangularpreset in Nx 11 still pulls in Codelyzer. With TSLint now being fully end-of-life, these dependencies are obsolete. Uninstall thecodelyzerandtslintpackages.Via the NPM CLI:
npm uninstall codelyzer tslintVia the PNPM CLI:
pnpm remove codelyzer tslintVia the Yarn CLI:
yarn remove codelyzer tslintA more durable alternative is to add a
preinstallscript that permanently erases Codelyzer and TSLint even when generators attempt to restore them.Via the NPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(npm uninstall codelyzer || echo ✅ Codelyzer is already removed.) && (npm uninstall tslint || echo ✅ TSLint is already removed.)';" npm installVia the PNPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(pnpm remove codelyzer || echo ✅ Codelyzer is already removed.) && (pnpm remove tslint || echo ✅ TSLint is already removed.)';" pnpm installVia the Yarn CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(yarn remove codelyzer || echo ✅ Codelyzer is already removed.) && (yarn remove tslint || echo ✅ TSLint is already removed.)';" yarn install -
Turn on Angular strict mode.
We recommend keeping both TypeScript and Angular in strict mode. Strict mode applies to both application and library projects.
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:application'].strict = true;" npx json -I -f angular.json -e "this.schematics['@nrwl/angular:library'].strict = true;" -
Select the unit test runner.
Nx ships with first-class support for both Jest and Karma in Angular application and library projects.Choose Jest:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:application'].unitTestRunner = 'jest';" npx json -I -f angular.json -e "this.schematics['@nrwl/angular:library'].unitTestRunner = 'jest';"Choose Karma:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:application'].unitTestRunner = 'karma';" npx json -I -f angular.json -e "this.schematics['@nrwl/angular:library'].unitTestRunner = 'karma';" -
Select the end-to-end test runner.
For end-to-end tests in Angular applications, Nx supports Cypress and Protractor out of the box.Choose Cypress:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular'].application.e2eTestRunner = 'cypress';"Choose Protractor:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular'].application.e2eTestRunner = 'protractor';" -
Merge the schematics defaults.
When you invokecreate-nx-workspacewith--preset=angular --linter=eslintin Nx 11.0.18, the workspace gets duplicate entries for the default Angular application and library schematics insideangular.json. Those duplicates break the configuration. This needs to be fixed before anything else.Merge the Angular application schematic defaults:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:application'].linter = this.schematics['@nrwl/angular'].application.linter; delete this.schematics['@nrwl/angular'].application;"Merge the Angular library schematic defaults:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:library'].linter = this.schematics['@nrwl/angular'].library.linter; delete this.schematics['@nrwl/angular'].library;" -
Recreate the application and end-to-end test projects when applying non-default runners.
If you picked Karma and Protractor instead of Jest and Cypress, the original application and end-to-end test projects must be removed and regenerated.Remove the end-to-end test and application projects:
nx generate @nrwl/workspace:remove booking-app-e2e nx generate @nrwl/workspace:remove booking-appGenerate both projects again:
nx generate @nrwl/angular:application --name=booking-app --prefix=booking --no-interactiveRemove any root-level Jest configuration files:
rm jest.config.js rm jest.preset.js -
Assign project tags.
Add tags to the freshly generated application and end-to-end test projects.
npx json -I -f nx.json -e "this.projects['booking-app'].tags = ['type:app','scope:booking'];" npx json -I -f nx.json -e "this.projects['booking-app-e2e'].tags = ['type:e2e','scope:booking'];" -
Apply strict Angular build budgets.
Nx 11.0.18 keeps build budgets unchanged even when Angular strict mode is on. We therefore mirror the budgets used by Angular CLI 11 in strict mode.The main bundle warns at 500 KB and errors at 1 MB; component styles warn at 2 KB and error at 4 KB.
npx json -I -f angular.json -e "this.projects['booking-app'].architect.build.configurations.production.budgets = [{ type: 'initial', maximumWarning: '500kb', maximumError: '1mb' }, { type: 'anyComponentStyle', maximumWarning: '2kb', maximumError: '4kb' }];" -
Create a workspace library.
We add an Angular library to confirm that the configuration holds for libraries as well.
nx generate @nrwl/angular:library --name=feature-flight-search --directory=booking --prefix=booking --tags="type:feature,scope:booking" --buildable --enable-ivy --no-interactiveThe library is set up as buildable and Ivy-based, though not publishable, so that we benefit from Nx 11's incremental builds and computation caching.
-
Remove Codelyzer again.
Angular CLI 11 injects Codelyzer by default during workspace or application generation, so we need to uninstall it once more.
Via the NPM CLI:
npm uninstall codelyzerVia the PNPM CLI:
pnpm remove codelyzerVia the Yarn CLI:
yarn remove codelyzer -
Confirm linting works.
Execute thelinttarget against all projects to confirm ESLint with angular-eslint is operational.
nx run-many --target=lint --all
The result of this flow is an Nx workspace with one Angular application and one Angular library. Using the angular preset puts us on version 1 of the Nx workspace format, identical to Angular CLI's. The vocabulary stays the same: builders, schematics, and architect targets.
Inspecting angular.json confirms that each lint target is wired to the @nrwl/linter:eslint executor.
The root .eslintrc.json references the @nrwl/nx/typescript ESLint plugin. The per-project ESLint configuration files for the application and the library should include the @nrwl/nx/angular, @nrwl/nx/angular-template, and @angular-eslint/template/process-inline-templates plugins.
Migrating an existing Nx 10 Angular workspace that uses ESLint
Workspaces that rely on ESLint already are migrated to angular-eslint as part of jumping to Nx 11.
-
Generate an Nx 10 workspace with the
angularpreset.
For this walkthrough, we create a fresh Nx Angular workspace with one application.Via the NPM CLI:
npm init nx-workspace@10 nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=npm --linter=eslintVia the PNPM CLI:
pnpm init nx-workspace@10 nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=pnpm --linter=eslintKeep in mind that PNPM is supported only from Nx 11 onward.
Via the Yarn CLI:
yarn global add create-nx-workspace@10 create-nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=yarn --linter=eslint -
Remove Codelyzer and TSLint.
Codelyzer and TSLint ship with Nx by default. Since TSLint has reached its end of life, it is time to say goodbye. Uninstallcodelyzerandtslint.Via the NPM CLI:
npm uninstall codelyzer tslintVia the Yarn CLI:
yarn remove codelyzer tslintAlternatively, add a
preinstallscript that strips out Codelyzer and TSLint on every install even when generators re-insert them.Via the NPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(npm uninstall codelyzer || echo ✅ Codelyzer is already removed.) && (npm uninstall tslint || echo ✅ TSLint is already removed.)';" npm installVia the PNPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(pnpm remove codelyzer || echo ✅ Codelyzer is already removed.) && (pnpm remove tslint || echo ✅ TSLint is already removed.)';" pnpm installVia the Yarn CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(yarn remove codelyzer || echo ✅ Codelyzer is already removed.) && (yarn remove tslint || echo ✅ TSLint is already removed.)';" yarn install -
Merge the schematics defaults.
In Nx 11.0.18, using--preset=angular --linter=eslintwith create-nx-workspace again yields duplicate Angular application and library schematic defaults inangular.json. Duplicates make the configuration unusable. Fix this first.Merge the Angular application schematic defaults:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:application'].linter = this.schematics['@nrwl/angular'].application.linter; delete this.schematics['@nrwl/angular'].application;"Merge the Angular library schematic defaults:
npx json -I -f angular.json -e "this.schematics['@nrwl/angular:library'].linter = this.schematics['@nrwl/angular'].library.linter; delete this.schematics['@nrwl/angular'].library;" -
Add a workspace library.
We include an Angular library so the example feels closer to a real project.
nx generate @nrwl/angular:library feature-flight-search --directory=booking --prefix=booking --tags="type:feature,scope:booking" --buildable --no-interactive -
Uninstall Codelyzer.
When Angular CLI 11 creates a workspace or application, it also adds Codelyzer by default, so remove it again.Via the NPM CLI:
npm uninstall codelyzerVia the Yarn CLI:
yarn remove codelyzer -
Upgrade to Nx 11.
The update to Nx 11 brings angular-eslint automatically for those workspaces already using ESLint.Via the NPM CLI:
nx migrate @nrwl/workspace npm install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json npm install rm migrations.jsonVia the PNPM CLI:
nx migrate @nrwl/workspace pnpm install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json pnpm install rm migrations.jsonVia the Yarn CLI:
nx migrate @nrwl/workspace yarn install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json yarn install rm migrations.json -
Verify linting.
Run thelinttarget for every project to confirm angular-eslint is working.
nx run-many --target=lint --all -
Bump angular-eslint.
Nx 11.0.18 installs angular-eslint 0.8.0-beta.1; we update to the latest release now.Via the NPM CLI:
npm install --save-dev @angular-eslint/eslint-plugin@latest @angular-eslint/eslint-plugin-template@latest @angular-eslint/template-parser@latestVia the PNPM CLI:
pnpm add --save-dev @angular-eslint/eslint-plugin@latest @angular-eslint/eslint-plugin-template@latest @angular-eslint/template-parser@latestVia the Yarn CLI:
yarn add @angular-eslint/eslint-plugin@latest @angular-eslint/eslint-plugin-template@latest @angular-eslint/template-parser@latest -
Re-verify linting.
Execute thelinttarget for all projects again to ensure angular-eslint operates correctly at the newer version.
nx run-many --target=lint --all
Migrating an existing Nx 10 Angular workspace that uses TSLint
As of Nx 11.0.18, there are no schematics that take an Nx Angular workspace using TSLint and automatically convert it to ESLint with angular-eslint.
The workaround is to apply the TSLint-to-ESLint migration schematics provided by angular-eslint itself, then handle several adjustments by hand so the final state matches what a fully migrated Nx Angular workspace would look like.
This example assumes the default test runners for the angular preset, which are Cypress and Jest. With Protractor and Karma, only the end-to-end test project configuration changes. If you want to compare ESLint setups, generate a brand-new Nx workspace with Karma, Protractor, and ESLint as discussed earlier in this article.
Be aware that the
angularpreset in this guide relies onangular.json. The angular-eslint migration schematics do not understand Nx workspaces that useworkspace.json.
-
Create an Nx 10 workspace with the
angularpreset.
We begin with a new Nx 10 workspace for the sake of demonstration. If a workspace already exists, adapt these steps to its specifics.Via the NPM CLI:
npm init nx-workspace@10 nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=npm --linter=tslintVia the PNPM CLI:
pnpx create-nx-workspace@10 nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=pnpm --linter=tslintPNPM is only available from Nx 11 onward.
Via the Yarn CLI:
yarn global add create-nx-workspace@10 create-nx-workspace nrwl-airlines --npm-scope=nrwl-airlines --preset=angular --app-name=booking-app --strict --no-nx-cloud --style=css --package-manager=yarn --linter=tslint -
Add an Angular workspace library.
This library project exists purely for the example. If you already have a workspace, this step is unnecessary.
nx generate @nrwl/angular:library --name=feature-flight-search --directory=booking --prefix=booking --tags="type:feature,scope:booking" --buildable --no-interactive -
Upgrade to Nx 11.
This step is technically optional. All of the actions that follow work identically on Nx 10.Via the NPM CLI:
nx migrate @nrwl/workspace npm install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json npm install rm migrations.jsonVia the PNPM CLI:
nx migrate @nrwl/workspace pnpm install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json pnpm install rm migrations.jsonVia the Yarn CLI:
nx migrate @nrwl/workspace yarn install # Good point in time to review migrations.json and make a commit before applying selected migrations nx migrate --run-migrations=migrations.json yarn install rm migrations.json -
Shift to angular-eslint.
First, renametsconfig.base.jsontotsconfig.jsontemporarily. The angular-eslint migration schematics are not built for solution-style TypeScript setups, which Nx has used since version 10.0.
mv tsconfig.base.json tsconfig.jsonNow execute the angular-eslint schematics to install the required dev dependencies, such as
eslint-plugin-*,@angular-eslint/*, and@typescript-eslint/*.Via the NPM CLI:
npm install --save-dev @angular-eslint/schematics nx generate @angular-eslint/schematics:ng-addVia the PNPM CLI:
pnpm add --save-dev @angular-eslint/schematics nx generate @angular-eslint/schematics:ng-addVia the Yarn CLI:
yarn add @angular-eslint/schematics nx generate @angular-eslint/schematics:ng-addThis may downgrade the
eslintversion that Nx installed. If so, restore the version Nx brought in. For instance:Via the NPM CLI:
npm install --save-dev eslint@7.10.0Via the PNPM CLI:
pnpm add --save-dev eslint@7.10.0Via the Yarn CLI:
yarn add eslint@7.10.0After that, run angular-eslint's converter for every Angular application and library project in the workspace.
Depending on your TSLint rules, you may see warnings such as this one:
WARNING: Within "tslint.json", the following 1 rule(s) did not have known converters in https://github.com/typescript-eslint/tslint-to-eslint-config - nx-enforce-module-boundaries You will need to decide on how to handle the above manually, but everything else has been handled for you automatically.Regarding the
nx-enforce-module-boundariesrule, the only rule that warns us in our example workspace, there is no cause for alarm because the root TSLint file stays until the very last step. That rule serves thenx workspace-lintcommand.In the ESLint world, the counterpart is
@nrwl/nx/enforce-module-boundaries, which we add to the root ESLint config during a later step.You can either run the generator by hand for each project:
# Migrate booking-app rules to angular-eslint nx generate @angular-eslint/schematics:convert-tslint-to-eslint booking-app # Migrate booking-app-e2e rules to angular-eslint nx generate @angular-eslint/schematics:convert-tslint-to-eslint booking-app-e2e # Migrate booking-feature-flight-search rules to angular-eslint nx generate @angular-eslint/schematics:convert-tslint-to-eslint booking-feature-flight-searchor cycle through the project names from
angular.jsonand invoke the generator inside a loop.A PowerShell version:
foreach ($project in (Get-Content angular.json | ConvertFrom-Json -AsHashtable).projects.GetEnumerator()) { nx generate @angular-eslint/schematics:convert-tslint-to-eslint $project.Name }A Bash version:
for project in $(cat angular.json | npx json projects | npx json -M -a key); do nx generate @angular-eslint/schematics:convert-tslint-to-eslint $project; doneFinally, put
tsconfig.base.jsonback in place.
mv tsconfig.json tsconfig.base.json -
Adapt angular-eslint for the Nx workspace.
Start by removing unneeded dev dependencies.
Via the NPM CLI:
npm uninstall @angular-eslint/builder @angular-eslint/schematicsVia the PNPM CLI:
pnpm remove @angular-eslint/builder @angular-eslint/schematicsVia the Yarn CLI:
yarn remove @angular-eslint/builder @angular-eslint/schematicsThen install the necessary dev dependencies.
Via the NPM CLI:
npm install --save-dev @nrwl/eslint-plugin-nx eslint-config-prettier eslint-plugin-cypressVia the PNPM CLI:
pnpm add --save-dev @nrwl/eslint-plugin-nx eslint-config-prettier eslint-plugin-cypressVia the Yarn CLI:
yarn add --dev @nrwl/eslint-plugin-nx eslint-config-prettier eslint-plugin-cypressNow set up the root ESLint configuration.
# Ignore all files not matched in overrides npx json -I -f .eslintrc.json -e "this.ignorePatterns = ['**/*'];" # Support ESLint plugins from `@nrwl/eslint-plugin-nx` npx json -I -f .eslintrc.json -e "this.plugins = ['@nrwl/nx'];" # Include tsx files # Can be left out from an Angular-only workspace npx json -I -f .eslintrc.json -e "this.overrides[0].files = ['*.ts', '*.tsx'];" # Match all TypeScript project configuration files npx json -I -f .eslintrc.json -e "this.overrides[0].parserOptions.project = './tsconfig.*?.json';" # This setting is not used by the Nrwl Linter npx json -I -f .eslintrc.json -e "delete this.overrides[0].parserOptions.createDefaultProgram;" # Replace angular-eslint plugins with the Nx TypeScript ESLint plugin as it uses them internally npx json -I -f .eslintrc.json -e "this.overrides[0].extends = ['plugin:@nrwl/nx/typescript'];" # Remove component template rule as this is defined in project-specific ESLint configurations npx json -I -f .eslintrc.json -e "this.overrides = this.overrides.slice(0, 1);" # Use Nx JavaScript ESLint plugin for js and jsx files # Can be left out from an Angular-only workspace npx json -I -f .eslintrc.json -e "this.overrides = [...this.overrides, { files: ['*.js', '*.jsx'], extends: ['plugin:@nrwl/nx/javascript'], rules: {} }];" # Remove angular-eslint rules that are added to project-specific ESLint configurations npx json -I -f .eslintrc.json -e "delete this.overrides[0].rules['@angular-eslint/component-selector'];" npx json -I -f .eslintrc.json -e "delete this.overrides[0].rules['@angular-eslint/directive-selector'];"Last for the root config is ensuring our workspace lint rules (and any others angular-eslint warned about) are merged in.
# This is where we configure the workspace lint rules # Refer to the root TSLint configuration npx json -I -f .eslintrc.json -e "this.overrides = [{ files: ['*.ts', '*.tsx', '*.js', '*.jsx'], rules: { '@nrwl/nx/enforce-module-boundaries': ['error', { enforceBuildableLibDependency: true, allow: [], depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }] }] } }, ...this.overrides];"It is time to wire up the ESLint config for each project. First, the
booking-appproject.
# Add Nx Angular ESLint plugin and the ESLint inline component template processor npx json -I -f apps/booking-app/.eslintrc.json -e "this.overrides[0].extends = ['plugin:@nrwl/nx/angular', 'plugin:@angular-eslint/template/process-inline-templates'];" # Match all TypeScript project configuration files npx json -I -f apps/booking-app/.eslintrc.json -e "this.overrides[0].parserOptions.project = [this.overrides[0].parserOptions.project[0].replace('/tsconfig.app.json', '/tsconfig.*?.json')];" # This setting is not used by the Nrwl Linter npx json -I -f apps/booking-app/.eslintrc.json -e "delete this.overrides[0].parserOptions.createDefaultProgram;" # Use the ESLint component template processor and recommended component template rules from angular-eslint npx json -I -f apps/booking-app/.eslintrc.json -e "this.overrides[1].extends = ['plugin:@nrwl/nx/angular-template', 'plugin:@angular-eslint/template/recommended'];"Then we handle
booking-feature-flight-search. The modifications are identical to those forbooking-app, except that this config sits three levels deep, so the relative path to the root ESLint config must be corrected.
# Correct path to root ESLint configuration npx json -I -f libs/booking/feature-flight-search/.eslintrc.json -e "this.extends = '../' + this.extends;" # Add Nx Angular ESLint plugin and the ESLint inline component template processor npx json -I -f libs/booking/feature-flight-search/.eslintrc.json -e "this.overrides[0].extends = ['plugin:@nrwl/nx/angular', 'plugin:@angular-eslint/template/process-inline-templates'];" # Match all TypeScript project configuration files npx json -I -f libs/booking/feature-flight-search/.eslintrc.json -e "this.overrides[0].parserOptions.project = [this.overrides[0].parserOptions.project[0].replace('/tsconfig.lib.json', '/tsconfig.*?.json')];" # This setting is not used by the Nrwl Linter npx json -I -f libs/booking/feature-flight-search/.eslintrc.json -e "delete this.overrides[0].parserOptions.createDefaultProgram;" # Use the ESLint component template processor and recommended component template rules from angular-eslint npx json -I -f libs/booking/feature-flight-search/.eslintrc.json -e "this.overrides[1].extends = ['plugin:@nrwl/nx/angular-template', 'plugin:@angular-eslint/template/recommended'];"Finally, set up ESLint for
booking-app-e2e.
# Use rules recommended by Cypress npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "this.extends = ['plugin:cypress/recommended', this.extends];" # Delete rule for component templates npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "this.overrides = this.overrides.slice(0, 1);" # Add rules specifically for the Cypress plugin loader npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "this.overrides = [{ files: ['src/plugins/index.js'], rules: { '@typescript-eslint/no-var-requires': 'off', 'no-undef': 'off' } }, ...this.overrides];" # Match all TypeScript project configuration files npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "this.overrides[1].parserOptions.project = [this.overrides[1].parserOptions.project[0].replace('/tsconfig.app.json', '/tsconfig.*?.json')];" # This setting is not used by the Nrwl Linter npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "delete this.overrides[1].parserOptions.createDefaultProgram;" # Remove Angular declarable rules npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "delete this.overrides[1].rules['@angular-eslint/component-selector'];" npx json -I -f apps/booking-app-e2e/.eslintrc.json -e "delete this.overrides[1].rules['@angular-eslint/directive-selector'];"Open
apps/booking-app-e2e/src/support/commands.tsand insert the comment below right before the line beginning withdeclare namespace Cypress {:
// eslint-disable-next-line @typescript-eslint/no-namespaceIn that same file, drop this comment before the line containing
interface Chainable<Subject> {:
// eslint-disable-next-line @typescript-eslint/no-unused-vars -
Swap in the Nrwl Linter builder.
The last configuration change is replacing@angular-eslint/builder:lintwith@nrwl/linter:eslintin the workspace config.
# Use Nrwl Linter npx json -I -f angular.json -e "this.projects['booking-app'].architect.lint.builder = '@nrwl/linter:eslint';" npx json -I -f angular.json -e "this.projects['booking-feature-flight-search'].architect.lint.builder = '@nrwl/linter:eslint';" npx json -I -f angular.json -e "this.projects['booking-app-e2e'].architect.lint.builder = '@nrwl/linter:eslint';" # Only lint js and ts files in the end-to-end test project npx json -I -f angular.json -e "this.projects['booking-app-e2e'].architect.lint.options.lintFilePatterns = [this.projects['booking-app-e2e'].architect.lint.options.lintFilePatterns[0].replace('*.ts', '*.{js,ts}')];" -
Get rid of Codelyzer and TSLint.
Via the NPM CLI:
npm uninstall codelyzer tslint rm tslint.jsonVia the Yarn CLI:
yarn remove codelyzer tslint rm tslint.jsonOr use a
preinstallscript so that Codelyzer and TSLint are removed repeatedly, even when generators try to restore them.Via the NPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(npm uninstall codelyzer || echo ✅ Codelyzer is already removed.) && (npm uninstall tslint || echo ✅ TSLint is already removed.)';" npm installVia the PNPM CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(pnpm remove codelyzer || echo ✅ Codelyzer is already removed.) && (pnpm remove tslint || echo ✅ TSLint is already removed.)';" pnpm installVia the Yarn CLI:
npx json -I -f package.json -e "this.scripts.preinstall = '(yarn remove codelyzer || echo ✅ Codelyzer is already removed.) && (yarn remove tslint || echo ✅ TSLint is already removed.)';" yarn install -
Verify linting.
Invoke thelinttarget on all projects to confirm everything works with ESLint and angular-eslint.
nx run-many --target=lint --all
Conclusion
The empty preset for Nx stands out because it lands on the new workspace.json version 2 schema, which uses executors, generators, and targets. This setup is flexible and plays nicely with angular-eslint.
Alternatively, the angular preset produces a workspace that continues to use angular.json.
An Nx 10 workspace already on ESLint makes the journey to Nx 11 painless: angular-eslint is installed and configured for every existing ESLint-based project during the upgrade.
An Nx 10 workspace on TSLint upgrades to Nx 11 without friction, but there is no automated TSLint-to-angular-eslint migration yet in Nx 11.0.18.
That said, Angular CLI workspaces do have migration paths. Those migrations are a reliable springboard for installing angular-eslint and generating the required ESLint configs and plugins.
To manually bring angular-eslint into an Nx workspace, adjust the ESLint configs so they mirror what a new Nx workspace would have and switch from the angular-eslint builder to the Nrwl Linter.
Regardless of your current stack, Codelyzer and TSLint can be retired today in favor of angular-eslint.
Some Codelyzer rules for Angular-specific TSLint checks have no matching angular-eslint rule yet. At publication time, these rules remain unimplemented:
angular-whitespacecontextual-decoratorimport-destructuring-spacingno-unused-cssprefer-inline-decoratortemplate-accessibility-alt-texttemplate-accessibility-label-fortemplate-accessibility-table-scopetemplate-click-events-have-key-eventstemplate-conditional-complexitytemplate-no-any
Why the rush to leave TSLint behind? On December 1st, 2020, TSLint officially reached its end of life. No pull requests or issues will ever be merged or answered again. That means TSLint 6.1.3 — the absolute final release — can be broken at any moment by a new version of Angular, TypeScript, Node.js, or any other dependency. TSLint was already deprecated two years ago.
Recognitions
Credit is due to James Henry for his work on angular-eslint, as well as to Nrwl and James Henry for bringing angular-eslint support into Nx.
