How to Set Up ESLint, Prettier, StyleLint, and lint-staged in Next.js
A linter is a tool that scans code for potential issues. This is invaluable with a programming language like JavaScript which is so loosely typed.
Even for TypeScript, which is a strongly typed language whose compiler does a great job of detecting errors at compile time, linters such as ESLint have plugins that catch problems not caught by the compiler.
When you generate a new app using the Next.js CLI (npx create-next-app
), ESLint is configured by default. But there are several problems with the linting setup generated by create-next-app
:
If you choose SCSS for styling, you should use Stylelint in the build process to lint CSS or SCSS stylesheets. But it’s not set up automatically.
If instead you opt for Tailwind for styling, you should set up the Tailwind plugin for ESLint. But again, this isn’t done in the generated ESLint configuration.
If you choose TypeScript, then in Next.js v14 and below, TypeScript-specific ESLint rules are not configured, contrary to what the documentation states. While a Next.js v15 app has these set up, I would still tweak the setup further with the more powerful linting rules provided by the typescript-eslint project.
And finally, Prettier is not set up. Prettier is a code formatting tool. It can prevent inconsistently formatted code from getting into the code repository, which would make comparisons between different versions of the same file difficult. Also, nicely formatted code is easier to work with. So this is a pretty big omission.
In this tutorial, I'll show you how I set up linting and formatting in my Next.js projects in a way that addresses the issues above. I’ll also teach you how to install and configure some related VS Code extensions for coding assistance.
To follow along, you can either use a Next.js project you already have, or generate a new app by running npx create-next-app
on the terminal.
If you’re scaffolding a new app, your choices are up to you (defaults are fine) but make sure to choose YES in response to the question about whether you’d like to use ESLint:
If you are following along with an existing app rather than a new one, upgrade it by running the following command in app root:
npm i next@latest react@latest react-dom@latest eslint-config-next@latest
npm i --save-dev eslint
This will avoid versioning conflicts down the line.
If you cannot upgrade to the latest version, you’ll need to specify versions for packages that will be installed in this tutorial to get around any version conflicts. Be warned that this can be frustrating.
Now you’re ready to open up the app in your code editor and proceed as follows.
Prerequisites
I assume that you know how to:
write a basic Next.js app with two or more pages.
install additional NPM packages into your app
Table of Contents
Set Up Prettier
Prettier is an opinionated code formatter that can format pretty much any file (.html
, .json
, .js
, .ts
, .css
, .scss
and so on).
Set it up in yuor app as follows:
Install Prettier:
npm install --save-dev prettier
If you chose Tailwind for styling when generating the app, then install
prettier-plugin-tailwindcss
:npm install --save-dev prettier-plugin-tailwindcss
This package is a Prettier plugin and provides rules for reordering of Tailwind classes used in a
class
orclassName
attribute according to a canonical ordering. It helps keep the ordering of Tailwind classes used in the markup consistent.%[https://youtu.be/tQkBJXwzY8A?autoplay=1]
Create
.prettierrc.json
in youyr project root. If you’re using SCSS for styling, paste the following snippet into this file:{ "singleQuote": true, "jsxSingleQuote": true }
If you’re using Tailwind instead, paste the following into
.prettierrc.json
:{ "plugins": ["prettier-plugin-tailwindcss"], "singleQuote": true, "jsxSingleQuote": true }
Create
.prettierignore
file in the app root, with the following content:node_modules .next .husky coverage .prettierignore .stylelintignore .eslintignore stories storybook-static *.log playwright-report .nyc_output test-results junit.xml docs
This file ensure that files which are not app code (that is, those which are not
.js
,.ts
,.css
files and so on.) do not get formatted. Otherwise Prettier will end up spending too much time processing files whose formatting you don't really care about.'prettierignore
(the file we just created),.eslintignore
, and.stylelintignore
have been ignored because these are plain text files with no structure so Prettier would complain that it cannot format them.Finally, I recommend that you follow the steps in this post to set LF as the EOL character, both in the repo and in your VS Code settings. Reasoning for this is given in the following subsection.
A note on line endings in Prettier
Prettier defaults to LF (Line Feed character) for line endings. This means that when it formats files, it will change all occurrences of the CRLF character sequence, if any, to LF.
LF is also the default in text editors and other tools in Unix-based systems (Linux, MacOS etc.). But on Windows, the default for line endings is CRLF (Carriage Return character, followed immediately by Line Feed character).
Windows tooling such as text and code editors can easily handle LF as line ending. But CRLF can be problematic for tools on Unix-based systems such as Linux and various flavours of Unix. Therefore it makes sense to only use LF as line endings in code as this would work on both Windows and Unix-based systems.
Configuring LF as the EOF character in Git repo and in code editors will bring your tooling in line with Prettier's default. It will also ensure that all files in the Git repo consistently have LF line endings. Thus if a contributor to your repo is on Windows which uses CRLF as EOL character, the code they add or modify in the repo would still use LF: the code editor would default new code files to LF; git
commit` would convert any CRLFs to LF when committing.
Finally, setting LF as the line endings for the whole repo would avoid strange things that happen when on Windows, Prettier retains its default of LF but Git and your code editor continue to use their default of CRLF for line endings:
When VS Code Prettier extension formats a file (for example, when the extension is set up to "autoformat on save"), it does not change CRLF line endings. But formatting the same file by running Prettier on the command line does change line endings to LF. This discrepancy can be annoying.
Git may show warnings like this when when you run
git add .
:
Set Up ESLint
Basics of ESLint configuration
ESLint comes with a number of linting rules out of the box. But you can also supplement these with ESLint plugins.
An ESLint plugin defines some linting rules. For example, if you look in the GitHub repo for Next's ESLint plugin, eslint-plugin-next, each file in the src/rules
folder defines a linting rule as a TypeScript function. The index.js
of the package then exports these rule functions in the rules
object in its default export:
module.exports = {
rules: {
'google-font-display': require('./rules/google-font-display'),
'google-font-preconnect': require('./rules/google-font-preconnect'),
'inline-script-id': require('./rules/inline-script-id'),
...
The basic way to use these rules in your app is to install the plugin package, then reference it in the ESLint configuration file in the app's root folder.
For example, we can use rules from the eslint-plugin-next
mentioned above by running npm install --save-dev eslint-plugin-next
, then placing the following content in the ESLint config file .eslintrc.json
in the app root:
{
plugins: ["next"],
"rules": {
"google-font-display": "warning",
"google-font-preconnect": "warning",
"inline-script-id": "error",
}
}
If you now run npx eslint .
in your app's root folder, ESLint will lint every JavaScript file in the app against each of the three rules configured above.
There are three severities you can assign to a rule when configuring it for use: off
, warning
and error
. As the snippet above shows, you enable a rule by assigning to it a severity of warning
or error
in the app's .eslintrc.json
.
When referencing a plugin in your app's ESLint configuration file, the prefix eslint-plugin-
in the plugin's package name is omitted. This is why the package that contains linting rules for Next.js, eslint-plugin-next
, is referenced only as "next"
in the snippet above.
Since it is quite cumbersome to configure a severity level - off
, warning
or error
- for every single rule from every plugin that you want to use, the norm is to reference an ESLint configuration object, or ESLint config for short, that is exported by an NPM package. This is a JavaScript object that declares plugins and configures rules from these with severity levels just as we did above.
For example, the default export from eslint-plugin-next
also contains several ESLint configs. Here is a another snippet from index.js
of the plugin, this time showing exported ESLint configs in addition to the rules
object for exporting rule functions:
module.exports = {
rules: {
'google-font-display': require('./rules/google-font-display'),
'google-font-preconnect': require('./rules/google-font-preconnect'),
'inline-script-id': require('./rules/inline-script-id'),
...
},
configs: {
recommended: {
plugins: ['@next/next'],
rules: {
// warnings
'@next/next/google-font-display': 'warn',
'@next/next/google-font-preconnect': 'warn',
...
// errors
'@next/next/inline-script-id': 'error',
'@next/next/no-assign-module-variable': 'error'
...
}
},
'core-web-vitals': {
plugins: ['@next/next'],
extends: ['plugin:@next/next/recommended'],
rules: {
'@next/next/no-html-link-for-pages': 'error',
'@next/next/no-sync-scripts': 'error',
},
},
}
As you can see, in addition to the rules (there are many more than those shown above), the plugin also exports two configs - recommended
and core-web-vitals
- that enable different selections of the rules defined in the plugin by assigning severity levels of error
or warning
to them.
The config that is normally used in Next.js projects is core-web-vitals
. We can use this config object in our app’s ESLint configuration file (.eslintrc.json
in app root) as follows:
{
"extends": ["plugin:next/core-web-vitals"]
}
Thus is much simpler than declaring the plugin in plugins
object and then assigning a severity level of error
or warning
to each rule from the plugin that we want to use.
Notice the difference between the configuration file - this is .eslintrc.json
- and config - this is an object that configures some rules from a plugin for use in a client project by assigning severities to selected rules.
Contents of the configuration file are themselves a config. But in configuration files, we do not typically import a plugin and configure all rules from it that we want to use. Instead we almost always import a well-known/trusted config object that is exported by an NPM package. Such a config object - one that is exported by an NPM package for use in ESLint configuration files (in other packages/apps) - is also known as a shareable config.
Typically, plugins - these define ESLint rules as JavaScript/TypeScript functions - also bundle their rules into one or more shareable configs. The recommended
config from plugin eslint-plugin-next
that we used above is just one such config.
Shareable configs do not only come from plugin packages, although it is customary for plugins to also export one or more shareable configs composed of their own rules. Other packages, whose names begin with eslint-config-
(as opposed to eslint-plugin-
) can provide one or more named configs.
Next.js provides one such package named eslint-config-next
. This re-exports configs recommended
and core-web-vitals
from the plugin. It also re-exports (in v15 and above of the package) a config of TypeScript linting rules from plugin typescript-eslint/eslint-plugin
. So instead of using recommended
config from the plugin like we have done above:
{
"extends": ["plugin:next/core-web-vitals"]
}
we could have installed the package eslint-config-next
and used that in .eslintrc.json
:
{
"extends": ["next/core-web-vitals"]
}
Since the package's name is not prefixed with plugin:
, ESLint considers it to be a config package, reconstructing the name as eslint-config-next
rather than as eslint-plugin-next
. Notice how with config packages also, we delete the canonical prefix eslint-config-
when referencing it in the ESLint configuration file.
It is possible to reference multiple shareable configs in extends
. In this case, all the rules from all configs are used - except where there are multiple configs that each provide a rule with the same name. In this case the last config, proceeding left to right, wins. This is to say where there is a naming conflict, ESLint will use the rule from the last config on the list.
It is possible to use ESLint configuration file formats other than JSON. You can provide the same information as in an .eslintrc.json
file in a JavaScript (.eslintrc.js
or .eslintrc.cjs
) or yaml (.eslintrc.yml
or .eslintrc.yaml
) file instead.
Also, ESLint has a new configuration file format often called flat config (which I haven't used here) where the config files are either JavaScript or TypeScript files.
Armed with an understanding of how to configure ESLint for use, you are ready to set up ESLint in your Next.js project. The sections below shows you how to do this.
ESLint Setup for TypeScript
If your app uses TypeScript, modify the ESLint configuration file (.esilntrc.json) as follows:
On the terminal, in app's root folder, run the following command:
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin typescript
@typescript-eslint/eslint-plugin
provides a number of linting rules for TypeScript files, as well as shareable configs, that augment the checking that the TypeScript compiler does.@typescript-eslint/parser
is a parser that allows ESLint to parse TypeScript files (by default it can only parser JavaScript files).
I am adding TypeScript compiler as a package - typescript
- because typescript-eslint
Getting Started instructions do the same.
In app root folder, rename
.eslintrc.json
to.eslintrc.js
. Then Replace contents of.eslintrc.js
in app root with the following:/* eslint-env node */ module.exports = { root: true, extends: [ 'next/core-web-vitals', ], plugins: ['@typescript-eslint', 'tailwindcss'], parser: '@typescript-eslint/parser', overrides: [ { files: ['*.ts', '*.tsx'], parserOptions: { project: ['./tsconfig.json'], projectService: true, tsconfigRootDir: __dirname, }, extends: [ 'next/core-web-vitals', 'plugin:@typescript-eslint/recommended', //'plugin:@typescript-eslint/recommended-type-checked', // 'plugin:@typescript-eslint/strict-type-checked', // 'plugin:@typescript-eslint/stylistic-type-checked', ] }, ], };
This is what the various lines of this file do:
/* eslint-env node */
stops ESLint from complaining that this is a CommonJS module. We have had to put this in because ESLint, as we have configured it here, does not allow CommonJS modules (which.eslintrc.js
is, seemodule.exports = ...
at the top) and expects modules in the project to be ES6.
root: true
says this is the topmost ESLint configuration file even though there may be nested ESLint configs in subfolders.
extends:
specifies various ESLint configs, each of which enables a collection of linting rules.
'next/core-web-vitals'
is a config provided by eslint-config-next
that bundles Next.js-specific rules (both for JavaScript and TypeScript, from an inspection of its code on GitHub).
The recommended-type-checked
config (used in a nested extends
within overrides
object - this is explained shortly) is provided by @typescript-eslint/eslint-plugin
. This plugin is part of the typescript-eslint project that publishes packages for linting rules and parsers to support linting of TypeScript files by ESLint.
The configs used is described here. It is a superset of the non-type checked versions of the config, recommended
. It adds linting rules which use TypeScript's type checking API for additional type information. These rules are more powerful than those contained in the base, non-type-checked recommended
config that only rely on the ESLint parser for TypeScript - package @typescript-eslint/parser
.
You might prefer to use the strict-type-checked
and stylistic-type-checked
configs, also provided by @typescript-eslint/eslint-plugin
. These are stricter than what I have used.
The least strict choice for TypeScript linting would probably be the recommended
config. This is what is re-exported by eslint-plugin-next
as config named typescript
and is referenced in Next.js instructions for setting up ESLint with TypeScript as next/typescript
(at least as of the time of this writing, September 2024). I prefer the config I have used instead.
parser: '@typescript-eslint/parser'
specifies the ESLint TypeScript parser to be used instead of the default Espree parser which cannot parser TypeScript files.
parserOptions:
tells the parser where to find the tsconfig.json
file. This information allows the rules in the type-checked config used above - recommended-type-checked
- to use TypeScript type checking APIs.
If we were using non-type-checked rules contained in other configs exported by the plugin, such as the recommended
config, we would not need to provide this information.
plugins: ['@typescript-eslint']
: I don't know what the purpose of this line is. It shouldn't be necessary and I have tested that the given ESLint configuration works fine without it. But it doesn't do any harm and was contained in an example in the plugin's documentation from which I adapted the above config. So I have kept it.
The overrides
section ensures that the TypeScript parser options that we’ve had to configure in order to support type-checked configs apply only to .ts
and .tsx
extensions (from this excellent StackOverflow answer). Otherwise, if parser
and parserOptions
objects had been at the top level, then running ESLint on the project would throw errors on .js
files.
This is a problem as we have several .js
config files including the .eslintrc.js
itself, so there will be linting errors. We can avoid these errors by using the override.
ESLint Setup for Tailwind
If your app uses Tailwind, modify the config as follows:
On the terminal, in app's root folder, run
npm install --save-dev eslint-plugin-tailwindcss
In ESLint config, add
"plugin:tailwindcss/recommended"
to the END ofextends
:{ "extends": ["next/core-web-vitals", ..., "plugin:tailwindcss/recommended"], }
In the ESLint config, add
"tailwindcss"
toplugins
and add arules
object as shown below:{ "plugins": [..., "tailwindcss"], "rules": { "tailwindcss/classnames-order": "off" }, }
If your app uses TYPESCRIPT, then also add
"plugin:tailwindcss/recommended"
to innerextends
insideoverrides
and duplicate therules
object insideoverrides
:{ ... overrides: [ { extends: ["next/core-web-vitals", ..., "plugin:tailwindcss/recommended"], rules: { 'tailwindcss/classnames-order': 'off', }, } }
In the Tailwind setup steps above, we have installed the package for the ESLint plugin for Tailwind, eslint-plugin-tailwindcss
, and used the config recommended
provided by the plugin.
eslint-plugin-tailwind
provides some useful linting rules for Tailwind CSS classes used in HTML or JSX/TSX markup. The biggest one for me is that if a class used in code is not a Tailwind class, there would be a linting error. This makes sense as when I am using Tailwind, I only use Tailwind-generated classes and do not define my own CSS classes.
The plugin also has a rule that checks that the sequence of Tailwind class names used in the class
or className
attribute in markup follows a canonical ordering. But we installed prettier-plugin-tailwindcss
in our Prettier configuration above which also reorders Tailwind class names. So we don’t need this rule in ESLint and it might conflict with what Prettier does in our workflow.
We’ll turn this rule off, which is named tailwindcss/classnames-order
, in the configuration above by declaring the plugin in plugins
object, then setting the rule to off
in the rules
object.
ESLint Setup for Prettier
On the terminal run:
npm install --save-dev eslint-config-prettier
In ESLint config, add
"prettier"
to the END ofextends
:{ "extends": ["next/core-web-vitals", ..., "prettier"] }
If your app uses TypeScript, then also add
"plugin:tailwindcss/recommended"
to the innerextends
insideoverrides
also:{ ... overrides: [ { "extends": ["next/core-web-vitals", ..., "prettier"], } }
In the Prettier setup steps above, the config referenced as
prettier
is the name of the NPM package eslint-config-prettier witheslint-config-
deleted. The default export from the package is an entire ESLint config object and this is the config we want to use.
So in this case, we do not suffix the name prettier
with /<name of config>
as we have done when referencing the named config core-web-vitals
from package eslint-config-next
when we referenced is as next/core-web-vitals
(see step 1 above).
This config switches off those rules in ESLint that conflict with the code formatting done by Prettier. This should be the last config in extends
.
- Create
.eslintignore
in the project root. It doesn't need to have any content for now, but will come in handy in the future if ever you need to add folders or files that should be ignored by ESLint (see the final section of this post for an example).
Set Up Stylelint
Stylelint is a linter for CSS and SCSS stylesheets.
If you are using SCSS and NOT Tailwind, then set up Stylelint by following the instructions below. This set up will work for both CSS and SCSS files:
On the terminal in project root run this command:
npm install --save-dev sass
Next.js has built-in SASS/SCSS support (so the Webpack config knows how to handle
.scss
and.sass
files). But you still need to install a version of thesass
package yourself, which is what we did above.Next, install packages for Stylelint and its rule configs:
npm install --save-dev stylelint stylelint-config-standard-scss stylelint-config-prettier-scss
Of these three packages:
stylelint
is the linter.stylelint-config-standard-scss
is a Stylelint config that provides linting rules. It uses the Stylelint plugin stylelint-css and extends configs stylelint-config-standard which defines rules for vanilla CSS, and stylelint-config-recommended-scss which defines SCSS specific rules. As a result, extending from this one config is enough to get linting support for both CSS and SCSS files.stylelint-config-prettier-scss
extends stylelint-config-prettier and turns off those Stylint rules that conflict with Prettier's code formatting. This should be declared last inextends:
array in.stylelintrc.json
(as shown below).
Now, create
.stylelintrc.json
in project root with the following contents:{ "extends": [ "stylelint-config-standard-scss", "stylelint-config-prettier-scss" ], "rules": { "selector-class-pattern": null } }
The
"extends"
section declares the two Stylelint configs whose NPM packages we installed in the previous step.
The "rules"
section is used to configure stylints rules. Here you can turn on or off, or configure the behavior of, individual Stylelint rules.
You can turn off a rule by setting it to null
, as I have done for "selector-class-pattern"
. I turned it off because it insists on having CSS classes in the so called kebab case (for example, .panel-quiz
instead of .panelQuiz
). I find it inconvenient for various reasons so I turned it off.
Next, create
.stylelintignore
in the project root with the following contents:styles/globals.css styles/Home.module.css coverage
I created this file so that the two stylesheets generated by the Next.js CLI which do not comply with the linting rules can get ignored (there might be a better way of doing this but this works for me). Also, files in
coverage
folder do not need to be linted and would likely throw up errors.
Set Up package.json
Scripts
- The most important script is
"build"
. The default command for this script,next build
, runs ESLint but not Prettier or (if you are using SCSS) Stylelint. So modify it inpackage.json
file as follows:
If your app uses Tailwind, then:
{
"scripts": {
"build": "prettier --check . && next build",
...
Otherwise, if your app uses SCSS, then:
{
"scripts": {
"build": "prettier --check . && stylelint --allow-empty-input \"**/*.{css,scss}\" && next build",
...
With this tweak to the existing build
script, we can run npm run build
either locally or in a CI/CD pipeline and it will fail not only on ESLint failure (this was the case before) but also on Prettier formatting or Stylelint failure.
Indeed if you deploy your app to Vercel, the default pipeline there also calls npm run build
. So when I introduced an error in one of my stylesheets, then deployed to Vercel, I got the following Stylelint error during deployment:
Note that I used the --check
flag with prettier
in the script (that is, I used the command prettier --check .
). This runs Prettier in check mode, so it only checks for correct formatting and does not change the formatting.
I did this because the build
script is what Vercel's deployment pipeline calls by default to build the code, and I don't want formatting to change during a CI build (nor do I want to tinker with Vercel defaults unless I absolutely have to).
To run Prettier locally to actually format the codebase, I define a separate build:local
script which is same as build
but runs Prettier without the --check
flag, as well as a separate format
script just to format with Prettier (but not build). These are set up below.
Set up the
"format"
script in yourpackage.json
. This formats the codebase with Prettier and comes in handy every now and then:{ "scripts": { ... "format": "prettier --write ."
I recommend setting up a
build:local
script as follows:
If your app uses Tailwind, then:
"build:local": "prettier --write . && next build"
Otherwise, if your app uses SCSS, then:
"build:local": "prettier --write . && stylelint --allow-empty-input \"**/*.{css,scss}\" && next build"
Since we cannot format the code with Prettier prior to executing next build
in the existing build
script (for reasons described above), we can use this script locally to format code then lint and build in one go.
Set Up lint-staged
lint-staged is a package that you can use to run formatting and linting commands on staged files in a Git repo. Staged files are those that have been added to the Git index using git add .
. These are the files that have changed since the last commit and will get committed when you next run git commit
.
Husky is the typical choice in Node.js packages for registering commands to run in Git hooks. For example, registering the command npx lint-staged
with Husky to run in the Git pre-commit hook means lint-staged will run automatically whenever you execute git commit
.
At that time, the formatter (Prettier) and linters (ESLint or Stylelint) that have been configured to run in the lint-staged configuration file will run on the staged files. If there are any errors during formatting checks or linting, the commit will fail.
Whenever git commit
fails due to linting errors, we can fix those, then run git add .
and git commit
again. Thus code only ever gets into the repo after it has been consistently formatted and verified to be free of linting errors. This is particularly advantageous in a team setting.
I prefer to only run prettier --check .
on staged files. In particular, I do not change formatting of staged files and do not lint during a commit, for the following reasons:
Reason for not formatting code: I almost always build and test my code before committing. Any code formatting should have happened prior to or during this local build and test.
I find the idea that code going into my repo should change automatically just as it is being committed after I have ascertained that any code changes are good to go, a little bit unappealing.
Reason for not linting code: With TypeScript code, the compiler can catch a huge number of issues in code. The additional linting rules provided by eslint-typescript/eslint-plugin
only supplement the checks made by the TypeScript compiler. So if I am linting code in staged files at commit time, I should build as well (so that the TypeScript compiler runs).
But building can be very time consuming on a large codebase. Besides, I almost always build and test (because of the way scripts in package.json have been set up above). Because of this, I don’t feel the need to repeat the lint and build process on staged files.
So, my personal preference is only to check for formatting on staged files, and neither reformat nor lint the code. This prevents inconsistently formatted code from getting into the Git repo where inconsistent formatting would make comparisons between different versions of the same file difficult.
So now, set up lint-staged and Husky as follows:
Install the lint-staged package:
npm install --save-dev lint-staged
Create
lint-staged.config.js
in project root with the following contents:/* eslint-env node */ const path = require('path'); const formatCommand = 'prettier . --check'; module.exports = { '*': formatCommand, };
Install the Husky NPM package.
npm install --save-dev husky
Run the following on the terminal in app root to configure Husky to run
lint-staged
whenevergit commit
runs (in Git's pre-commit hook):npx husky init echo "npx lint-staged" > .husky/pre-commit
You should now have a file
.husy/pre-commit
in your app's folder with only one line:npx lint-staged
.
Set UP VS Code Extensions
If you use VS Code as your code editor, you can install the following VS Code extensions to provide linting and formatting on file save and syntax highlight on linting errors:
Stylelint extension (if you're using SCSS and not Tailwind)
TaliwindCSS extension (if you are using Tailwind and not SCSS)
Put the following in a settings.json
file in the .vscode
folder in the project (you can of course put these settings in you User Preferences file also. You can access it from Command Palette Ctrl + P).
{
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[scss]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"stylelint.validate": ["css", "scss"],
"editor.formatOnSave": true
}
As they’re set up, the extensions will lint and format on Save.
Final Checks and Troubleshooting
Now it’s time to build and commit:
npm run format
npm run build
git add .
git commit -m "fix: set up linting and formatting"
Building and committing is a good sanity check for the setup we just did.
If anything had not been set up correctly, you might get errors either during build or at commit.
If you already had some code in the project, then there might be a few errors when you commit. Typically, these can be resolved by:
Adding folders or files to one of the
*ignore
files. For example, I already had some code in my project with Storybook installed. So I had to add folders.storybook
andstorybook-static
to each of.stylelintignore
,.eslintignore
and.prettierignore
as all three tools complained about them.stories storybook-static
Adding plugins for specific file types. For example, I had Gherkin
.feature
files in my project to describe integration tests. Prettier couldn't format these. So I added the prettier-plugin-gherkin by simply running:npm install prettier-plugin-gherkin --save-dev
Note that usually it is enough to install the package for a Prettier plugin for Prettier to locate it and additional configuration is not required.
Likewise, ESLint complained when it encountered
.cy.ts
files containing Cypress interaction tests for my app. To resolve this linting error, I installed the NPM package for Cypress ESLint plugin and configured it as described here (unlike Prettier, to get this ESLint package to work, some configuration was required).The typescript config might be too strict and there might be a lot of errors when you build, such as:
If you do not want to fix individual errors in your existing codebase, and they are too many to disable specific rules at error locations using ESLint comments (see below), then the simplest solution would be to disable the
@typescript-eslint/recommended-type-checked
config by commenting it out in.eslintrc.js
and uncommenting@typescript-eslint/recommended
which is less strict.Sometimes it is safe to turn off a linting rule at a specific line or for a whole file. While I am always wary of doing this, in a (deliberately bad) experimental code file, I had many instances of an error that VS Code ESLint extension pointed. This was not caught before but was now being pointed out because strict TypeScript linting rules had been enabled:
So I pressed
Ctrl + .
to Show Code Actions (I could instead have clicked the yellow lighbulb icon shown next to the issue), then selected “Disable@typescript/no-non-null-assertion
for the entire file”.This placed the comment
/* eslint-disable @typescript-eslint/no-non-null-assertion */
on top of my file to disable all instances of that particular error within the file:
Conclusion
This tutorial showed you how to configure linting and formatting tools in your Next.js app. I hope that it also gave you the background necessary both to understand the configurations given, and to customize them as needed.
Subscribe to my newsletter
Read articles from Naveed Ausaf directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by