How To Style Your Next.JS Projects EXACTLY Like Google (in TypeScript)
Learn how to utilize TypeScript, ESLint, Prettier, Husky & VS Code to style a Next.JS Project using Google's TypeScript Style Guide.
Introduction
Sticking to a consistent style guide is something that we all love doing as programmers. Whether it's spaces instead of tabs, double quotes instead of single, or putting your {
's on a new line (if you are a savage).
Sometimes, however, we can slip up and let small differences in our styling exist throughout our codebase. The problem arises when codebases become bigger and bigger over time, and small inconsistencies sneakily add up over the years.
In this guide I'm going to run through how you can:
- Setup your Next.JS projects using Typescript, ESLint, Prettier, and Husky.
- Lint and format your code to align to the style rules you defined in config.
- Auto-format and auto-style your code whenever you click save.
- Check if your code meets all of your style rules before you
git commit
. - Use and extend Google's Typescript style guidelines.
For video lovers
If you prefer to watch your content, or you're feeling a bit too sleepy to read ๐ด, I've also made this guide into a video tutorial, you can find that here
Goal
At the end of the guide, you'll have a project that uses Next.JS and TypeScript to enforce Google's Typescript style guidelines when it comes to linting and formatting.
Guide
Creating the Next.JS App
Firstly we'll need to initialize a new Next.JS application. Run the following command from the command line to do-so:
npx create-next-app code-like-google
Now, let's change directory into your newly created Next app.
cd code-like-google
And open it up in Visual Studio Code!
code .
Cleaning up the example code
To clean up the example code provided by the create-next-app
command, go ahead and:
- Delete the
api
folder and it's contents - Delete
_app.js
Setting up TypeScript
Next.js provides an integrated TypeScript experience out of the box, similar to an IDE.
To get started, create an empty tsconfig.json
file in the root of your project.
Then run npm run dev
from your command line.
shocked pikachu an error comes up!
Not to worry, we just need to install some packages to make it work. Run
npm install --save-dev typescript @types/react @types/node
Now we can go back and change our index.js
file to index.tsx
, and run npm run dev
again.
Next.js will automatically configure the tsconfig
file with default values for Next.JS.
Let's modify the tsconfig.json
file a little bit to match Google's standards. Modify it to the below:
{
"compilerOptions": {
"allowJs": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"declaration": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "preserve",
"lib": ["dom", "dom.iterable", "esnext"],
"module": "esnext",
"moduleResolution": "node",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"pretty": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"target": "es2018"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Great! We are done setting up TypeScript, feel free to hover over each of these values to find out more about what they do or find out more on this document.
Setting up ESLint
What is ESLint?
ESLint statically analyzes your code to quickly find problems. Many problems ESLint finds can be automatically fixed. ESLint fixes are syntax-aware so you won't experience errors introduced by traditional find-and-replace algorithms.
In simple terms, ESLint makes suggestions for you to avoid bugs in your code, for example, suggesting that you add a return type to functions that don't have one, or recommending you remove console.log
statements.
A full list of ESLint rules can be found here.
Some issues that ESLint finds are "auto-fixable", and later on, we'll be configuring ESLint to fix everything it can figure out itself whenever hit save.
To install ESLint, run
npm install eslint --save-dev
Then to configure ESLint, run:
npx eslint --init
Below are the settings that I chose to use in this guide, you can either choose to follow these settings or configure your own rules according to your personal preferences.
# Interactive
? How would you like to use ESLint? ...
> To check syntax, find problems, and enforce code style
? What type of modules does your project use? ...
> JavaScript modules (import/export)
? Which framework does your project use? ...
> React
? Does your project use TypeScript? ยป Yes
? Where does your code run? ...
โ Browser
? How would you like to define a style for your project? ...
> Use a popular style guide
? Which style guide do you want to follow? ...
> Google: https://github.com/google/eslint-config-google
? What format do you want your config file to be in? ...
> JavaScript
eslint-plugin-react@latest @typescript-eslint/eslint-plugin@latest eslint-config-google@latest eslint@>=5.16.0 @typescript-eslint/parser@latest
? Would you like to install them now with npm? ยป Yes
What just happened?
We've installed a number of npm packages to configure ESLint to lint TypeScript code and also extended eslint-config-google
to copy Google's linting rules.
You can take a look at what we created in the .eslintrc.js
file. ESLint will look for eslintrc.*
files and use them to enforce the rules that you have specified in the file.
If you followed the above example, we are extending
Google's ruleset.
Side Note: During this step, I encountered a weird bug where react version was not being detected. I appended the following code inside my module.exports
in eslintrc.js
to resolve it:
settings: {
react: {
version: "latest",
},
},
Setting up Prettier
Prettier is a code formatter.
It removes all original styling and ensures that all outputted code conforms to a consistent style.
It'll do things like adding a semicolon to the end of every statement, or make sure your indentation is consistent.
To install prettier, run:
npm install --save-dev --save-exact prettier
To avoid format conflicts between ESLint and Prettier, we'll also need this package, called eslint-config-prettier
.
It turns off all ESLint rules that are unnecessary or might conflict with Prettier.
npm install --save-dev eslint-config-prettier
One last thing to make Prettier cooperate with ESLint; add "prettier" to the extends
array in your eslintrc.js
file. So it now should look like this:
extends: ["plugin:react/recommended", "google", "prettier"],
Make sure to put it last, so it gets the chance to override other configs.
To customize Prettier, create a .prettierrc
file in the root of your directory.
Let's configure Prettier with the following in our .prettierrc
file:
{
"endOfLine": "lf",
"printWidth": 80,
"tabWidth": 2,
"trailingComma": "es5"
}
Bonus: .prettierignore and .eslintignore
Similarly to .gitignore
we can configure both ESLint and Prettier to ignore formatting or linting certain files or directories.
I set both of these files to the below:
.next
next-env.d.ts
node_modules
yarn.lock
package-lock.json
public
Configuring Visual Studio
Install Extensions
Inside Visual Studio, there are extensions for both ESLint and Prettier
Install both of these extensions in Visual Studio Code. (Ctrl
+ Shift
+ X
to open the extensions window in Visual Studio Code.)
Configuring Preferences
To configure these extensions on a User level, go to File > Preferences > Settings
or hit Ctrl
+ ,
Search "default formatter" in the search bar, and Editor: Default Fromatter
to Prettier - Code formatter
Next, search "format on" in the search bar, and tick Editor: Format on Paste
, and Editor: Format on Save
.
To test if everything worked, go to index.tsx
and press Alt
+ Shift
+ F
. (you may be given an option to select default formatter here, select Prettier)
If we've set everything up correctly it should auto-format your code.
(You may need to restart VS Code).
If you're following along with the guide, ESLint will have a few things to say about our index.tsx
file.
Not to worry, all that it's saying is that we need two things:
- React imported if we want to use JSX
- A JSDoc Comment to explain what the function does.
at the top, add :
import React from "react";
/**
* Home: The Landing page of the web app
* @return {JSX.Element} The JSX Code for the Home Page
*/
Formatting on save
We've implemented our standards and both ESLint and Prettier are going to help us stay consistent, but when there are auto-fixable problems ESLint can implement, I want them to be implemented whenever I hit save.
To achieve this, we can modify our VS Code settings for this project.
- Create a
.vscode
folder at the root of your directory - Within that folder, create a
settings.json
file. - Change your
settings.json
to:{ "editor.formatOnPaste": true, "editor.formatOnSave": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.fixAll.format": true } }
This is going to first lint, then format all of our code every time we hit save. It's also enabled formatting code on pasting code into our files and set Prettier as the default formatter for this project.
Using husky to run checks on git commit
We are going to be using husky to perform the following whenever a git commit is made:
- Check there are no Prettier warnings on our code.
- Check there are no ESLint warnings on our code.
- Check there are no errors compiling our code from TypeScript.
- Check we can build our project using
next build
To install husky, run:
npx husky-init
then
npm install
This will set up husky, modify package.json
, and create a sample pre-commit hook that we are going to modify.
Firstly, let's modify package.json
to add some scripts for what we would like to check.
In package.json
, I have the following scripts:
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"check-types": "tsc --pretty --noEmit",
"check-format": "prettier --check .",
"check-lint": "eslint . --ext ts --ext tsx --ext js",
"format": "prettier --write .",
"test-all": "npm run check-format && npm run check-lint && npm run check-types && npm run build",
"prepare": "husky install"
},
To summarise:
- check-types runs TypeScript's
tsc
CLI command and pretty prints any warnings/errors. - check-format asks Prettier to check all of our files (excluding the ones in .prettierignore) for formatting issues.
- check-lint asks ESLint to check for any linting warnings/errors on an .ts, .tsx or .js files.
- format tells prettier to automatically re-write all of our files with proper formatting
- test-all runs a number of the above commands in sequence.
Editing the pre-commit
hook
The pre-commit hook that is created when we initialized husky does exactly what it says; it runs prior to executing a git commit.
For example, if you run a git commit
command, this script would run first, then on its success, a commit would be executed. If the pre-commit hook fails, the commit does not go through.
This is what I've made the pre-commit script to contain:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo '๐๏ธ๐ท Styling, testing and building your project before committing'
# Check Prettier standards
npm run check-format ||
(
echo '๐คข๐คฎ๐คข๐คฎ Its F**KING RAW - Your styling looks disgusting. ๐คข๐คฎ๐คข๐คฎ
Prettier Check Failed. Run npm run format, add changes and try commit again.';
false;
)
# Check ESLint Standards
npm run check-lint ||
(
echo '๐ค๐๐๐ค Get that weak s**t out of here! ๐ค๐๐๐ค
ESLint Check Failed. Make the required changes listed above, add changes and try to commit again.'
false;
)
# Check tsconfig standards
npm run check-types ||
(
echo '๐คก๐โ๐คก Failed Type check. ๐คก๐โ๐คก
Are you seriously trying to write that? Make the changes required above.'
false;
)
# If everything passes... Now we can commit
echo '๐ค๐ค๐ค๐ค... Alright... Code looks good to me... Trying to build now. ๐ค๐ค๐ค๐ค'
npm run build ||
(
echo 'โ๐ท๐จโ Better call Bob... Because your build failed โ๐ท๐จโ
Next build failed: View the errors above to see why.
'
false;
)
# If everything passes... Now we can commit
echo 'โ
โ
โ
โ
You win this time... I am committing this now. โ
โ
โ
โ
'
I like to have a little fun with my messages as you can see... In a nutshell, all we are saying in this file is, before a commit:
- Check Prettier standards looks good (otherwise fail commit)
- Check ESLint standards looks good (otherwise fail commit)
- Check tsconfig standards looks good (otherwise fail commit)
- Try produce a
next build
(otherwise fail commit)
Conclusion
That's it! Now every time we save our file we'll auto-lint and auto-format. Not only that, every time we try to make a commit to git, we first have to pass a series of tests and face the gauntlet of being roasted by our own emojis!
Thanks for reading!
Find me at:
YouTube: youtube.com/channel/UCJae_agpt9S3qwWNED0KHcQ
Twitter: twitter.com/JarrodWattsDev
GitHub: github.com/jarrodwatts
LinkedIn: linkedin.com/in/jarrodwatts
Website: jarrodwatts.com