Get with the times & ditch TSLint in favor of ESLint in SharePoint Framework projects

Learn how to replace the long-deprecated TSLint for ESLint in SharePoint Framework projects.

By Last Updated: December 7, 2024 8 minutes read

Important: SPFx v1.15+ projects default to ESLint
Starting with the SharePoint Framework (SPFx) v1.15, new projects use ESLint instead of TSLint. Learn more from my video & associated blog post on the SPFx v1.15 release.
Important: 🚀 Check out our presets to simplify this process!

This post explains how to manually switch your SharePoint Framework projects from using TSLint to ESLint by installing packages, creating the ESLint config file, adding the new gulp task.

If this is interesting to you, make sure you check out our presets! We’ve created two presets depending if you use or don’t use React in your project, that will do the full project configuration for you!

Just run a single npm install command in your project depending on the type of project you’re working with and bask in your coding glory! Learn more in the following post:

👉 Introducing ESLint presets for SPFx projects

In my last post about Fixing the “can’t find custom rule directory: tslint-microsoft-contrib” error in SPFx projects, I explained a random error that can pop up with your SharePoint Framework (SPFx) projects as well as how to fix it. But in that post, I mentioned something in passing:

🤔 TSLint has been deprecated for over 2.5 years!

“The SharePoint Framework is still using TSLint, an extensible linter for TypeScript, even though it’s been deprecated for nearly 2.5 years.”

- Fix the "can’t find custom rule directory: tslint-microsoft-contrib" error in SPFx projects

That surprised a few SPFx developers! The TypeScript team, in their January 2019 roadmap post (see: microsoft/typescript#29288), stated they were committed to working towards a more unified developer experience across TypeScript & JavaScript. Part of this means they didn’t want to leverage special TypeScript tools, rather they wanted TypeScript to make JavaScript better.

At the time, TSLint was the de facto standard linter for TypeScript projects. With the TypeScript 2019 roadmap post, the TSLint team decided to deprecate their own tool and work to focus their efforts on contributing to ESLint:

🤔 TSLint deprecates TSLint

“In order to avoid bifurcating the linting tool space for TypeScript, we therefore plan to deprecate TSLint and focus our efforts instead on improving ESLint’s TypeScript support.”

- TSLint in 2019

Cool, but why does SPFx still use TSLint?

Good question, but unfortunately I can’t answer that question. It’s been asked before as you can see from issues in the sharepoint/sp-dev-docs issue list & from a UserVoice entry: SPFx: ESLint instead of TSLint.

If history has shown us anything with SPFx, they’re slow to adopt the latest, or even recent, tech. Remember how long it took to adopt support for Node.js v12 & v14? It only took 17 months to support Node.js v12 after it gained status as the active LTS version. But I digress…

Regardless… why do you have to wait for Microsoft to switch? You don’t!

You can swap TSLint out today and use ESLint, and in this post I’ll show you how!

Replace TSLint with ESLint in SharePoint Framework projects

Replace TSLint with ESLint in SharePoint Framework projects

But first, a word about dependencies…

Today, the current version of SPFx is v1.12.1 which defaults to use TypeScript v3.7. Due to the large dependency tree Microsoft adopted for the SPFx build toolchain, you can’t easily use the latest version of ESLint (v7), instead you’ll be stuck with ESLint v6 for the time being.

This isn’t a bad thing, I just mention it because if you’re reading the docs for ESLint, you should be aware of it as they default to the latest version.

You can get around this if you upgrade your project to TypeScript v3.9 though. To see how to do this, see my post: Use Different Versions of TypeScript in SPFx projects.

How to: swap out TSLint for ESLint in SPFx projects

For this post, I’m going to assume you’ve already created the default SPFx v1.12.1 project using no JavaScript framework (in other words: not a React project).

Remove TSLint from the project

The first step is to remove that deprecated TSLint tool from your project, as well as all related files.

Within the file ./gulpfile.js, locate the following line:

build.initialize(require('gulp'));

Add the following line immediately before the line that calls build.initialize():

// disable tslint
build.tslintCmd.enabled = false;

Finally, delete the ./tslint.json file from your project as you don’t need it anymore.

With TSLint removed, the next step is to install a few dependencies.

These add ESLint and a few plugins to support linting TypeScript projects with ESLint. These include the following:

  • eslint: the tool used to identify & report patterns found in your TypeScript code
  • @typescript-eslint/parser: An ESLint parser which leverages TypeScript ESTree to allow for ESLint to lint TypeScript source code.
  • @typescript-eslint/eslint-plugin: An ESLint plugin which provides lint rules for TypeScript codebases.
  • gulp-eslint: A gulp plugin for processing files with ESLint

You can install these using the following command:

I’ve broken the following command up on different lines for readability, but you need to run it on just one line.
npm install
  eslint@latest
  @typescript-eslint/parser@latest
  @typescript-eslint/eslint-plugin@latest
  gulp-eslint@latest
  --save-dev --save-exact

Implement the ESLint configuration file

The next thing you’ll need to do is create a configuration for ESLint. This serves the same role as the tslint.json file. Since SPFx projects already have a ./config folder, that seems like a natural place for all configuration stuff.

Create a new file ./config/eslint.json and add the following to it:

{
  "$schema": "https://json.schemastore.org/eslintrc.json",
  "root": true,
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2020,
    "sourceType": "module"
  },
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ]
}

Refer to ESLint: Configuring ESLint docs for details on this file, but remember you’re using an outdated version of ESLint.

Because our project is entirely TypeScript, we can tell ESLint to ignore JavaScript files. However, one thing ESLint v7 supports that ESLint v6 doesn’t support is specifying files you want to ignore in the configuration file using the ignorePatterns property (see ESLint: ignorePatterns in Config Files). This means we have to use the older .eslintignore option supported by ESLint v6.

Add the file ./.eslintignore to the root of your project and add the following to it:

**/*.js

Update Gulp

The last step is to update your project’s Gulp configuration to support a new eslint task as well as do what the default project did with TSLint: run ESLint as a subtask when you execute gulp build.

Within the ./gulpfile.js file, locate the lines you added to disable TSLint. Next, add the following immediately after that, but before the call to build.initialize():

// add eslint
const eslint = require('gulp-eslint');
const eslintSubTask = build.subTask('eslint-subTask', function (gulp, buildOptions, done) {
  return gulp.src(['src/**/*.{ts,tsx}'])
    .pipe(eslint('./config/eslint.json'))
    .pipe(eslint.format())
    .pipe(eslint.failAfterError());
});
build.rig.addPreBuildTask(build.task('eslint', eslintSubTask));

This first loads the ESLint gulp task and then creates a subtask. The subtask pipes all TypeScript & TypeScript Extended files through ESLint, using the configuration file we created. If it finds any issues with the code, the build will fail, matching the same experience we had in the default TSLint configuration in SPFx projects.

Finally, it adds the new ESLint task both as its own task that you can run on its own, but also as a subtask to the gulp build task. You can see the task by executing gulp –tasks:

new ESLint gulp task

Notice our new ESLint gulp task!

Let’s see how it works! Execute the task, either by entering gulp eslint or gulp build:

ESLint gulp task running

Successful execution of our ESLint gulp task

While everything is working, it seems the default code is ok. Let’s add a rule to our config to force some issues to appear. Within the ./config/eslint.json file, add the rule array-bracket-newline to the configuration file so it looks like the following:

{
  "$schema": "https://json.schemastore.org/eslintrc.json",
  "root": true,
  "ignorePatterns": "*.js",
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaVersion": 2020,
    "sourceType": "module"
  },
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "rules": {
    "array-bracket-newline":["error", "never"]
  }
}

This tells ESLint that all arrays should be defined on a single line, just like you see it listed for the rule. This will certainly throw some errors due to the code in our default webpart’s getPropertyPaneConfiguration() method.

Now rerun ESLint to see the results:

ESLint gulp task reporting errors

ESLint reporting errors

Fantastic, you’re now using ESLint!

“What if I’m using React in my SPFx project?”

Good question. There’s another ESLint plugin you’ll want to install, eslint-plugin-react, to get React specific linting rules for ESLint.

Save the work, use a preset!

We’ve created two presets to simplify the process of replacing TSLint in favor of ESLint in your SPFx project. Learn more in the following post:

👉 Introducing ESLint presets for SPFx projects

Improvements if you’re using TypeScript v3.9

If you’ve updated your SPFx project to use TypeScript v3.9, you can make a few changes to the steps above to implement a few optimizations.

If you haven’t already, upgrade your project to TypeScript v3.9. To see how to do this, see my post: Use Different Versions of TypeScript in SPFx projects.

Updated dependencies

If you already installed the dependencies using the script above, repeat that step to get the most current stuff available. You’ll see the two @typescript-eslint/* packages will jump from v2 to v4 and the eslint package will jump to v7.

Update the ESLint ignore file

ESLint v7 supports specifying the file patterns you want to ignore using a property in the config file, rather than a dedicated ignore file.

Add the following to your ./config/eslint.json file:

"ignorePatterns": "*.js",

Now you can delete the ./eslintignore file in the root of your project.

Congrats, you’re now leveraging the latest version of ESLint!