# How To Style Your Next.JS Projects EXACTLY Like Google (in TypeScript)

# 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

%[https://www.youtube.com/watch?v=sH93pQb9bWM]


## 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](https://www.typescriptlang.org/tsconfig).

## 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.](https://eslint.org/docs/rules/) 

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](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) ** and ** [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) **

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` + `,`

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1619675754932/C4XiAB7lV.png)

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`.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1619675740159/Spv9LOJBg.png)

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**)

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1619615022188/nKyviKUSh.png)

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.

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1619615307345/HVz4svg_J.png)

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.

1. Create a `.vscode` folder at the root of your directory
2. Within that folder, create a `settings.json` file.
3. 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](https://www.typescriptlang.org/docs/handbook/compiler-options.html) 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:

[Buy me a coffee ☕](https://www.buymeacoffee.com/jarrodwatts) 

YouTube: https://www.youtube.com/channel/UCJae_agpt9S3qwWNED0KHcQ

Twitter: https://twitter.com/JarrodWattsDev

GitHub: https://github.com/jarrodwatts

LinkedIn: https://www.linkedin.com/in/jarrodwatts/

Website: https://jarrodwatts.com/
