My NextJS Setup
Tags: react, typescript, nextjs, frontend
Published: 2020-09-28 10:18:57

If you are starting out with Next.js and Server Side Rendering for the first time, then the initial project setup may take a significant amount of your time. It is not likely that you will be working with plain Next.js. You should require some tooling and a manageable and scalable project structure. In this post, I will share a Next.js boilerplate structure that I am using. 

[Next.js](https://nextjs.org/) is a React framework that offers Server-Side Rendering (SSR) and Static Site Generation (SSG) along with some other handy features like:
- Incremental Static Generation
- TypeScript Support
- Fast Refresh
- Filesystem-based Routing
- API Routes
- Built-in CSS Support
- Code Splitting and Bundling

I will give a brief overview of my Next.js setup with TypeScript, ESLint, Jest, and TailwindCSS from scratch. This will give you a good starting point for your Next.js projects. So, If you are starting a new project in Next but you are not sure how to set it up then this post is for you. This might save you some time on the initial setup and get you up and running quickly. Let's get started.

## Installing NextJS
We will use `create-next-app` to generate your Next.js application. You need to have NodeJS 10.13 or later installed. We will use `npm` as a package manager. 

```shell
npx create-next-app my_next_app
```
This will create a fresh Next.js application in the `my_next_app` directory. The folder-structure of your app should look like this:
```
my_next_app
├── node_modules
├── package.json
├── package-lock.json
├── pages
│   ├── api
│   │   └── hello.js
│   ├── _app.js
│   └── index.js
├── public
│   ├── favicon.ico
│   └── vercel.svg
├── README.md
└── styles
    ├── globals.css
    └── Home.module.css
```
Now, we will change this structure a little bit. We will create a directory called `src` in the root of our project and move `pages`, `public` and `styles` directories in the `src` directory. We can also make directories like `components`, `helpers`, 'lib' etc in the `src` directory to organize everything properly. Now start our dev server.
```
npm run dev
```
This will run the Next.js development server on `127.0.0.1:3000`. If everything is fine then you should see the Next.js project starter page on your `localhost:3000`.

## Setting Up TypeScript
It is very easy to set up [TypeScript](https://www.typescriptlang.org/)  in your Next.js project. First, install TypeScript along with React and Node types.
```
npm install --save-dev typescript @types/react @types/node
```
Now, we can change the `.js` files to `.ts(x)` files. 
```
src/pages/api/hello.js -> hello.ts
src/pages/_app.js -> _app.tsx
src/pages/index.js -> index.tsx
```
Hope you get the idea. Now replace the content of your `src/pages/_app.tsx` with the following code:
```javascript
/* 
 * _app.tsx file
 */
import { AppProps } from 'next/app'

function App({ Component, pageProps }: AppProps ){
  return <Component {...pageProps} />
}

export default App
```
Like the above, we need to replace all the `js` code to its equivalent `ts` code. After that stop the dev server (if it's running) and start it again. Next.js will automatically detect TypeScript and generate a `tsconfig.json` file and a `next-env.d.ts` file for you. Your basic TypeScript setup is done.

## Setting up ESLint
For large TypeScript of JavaScript projects code consistency and following the best practices are very important. That's where [ESLint](https://eslint.org/) comes in. To setup ESLint in your Next.js application install ESLint as a `devDependency`
```shell
npm i -D eslint eslint-plugin-react @typescript-eslint/eslint-plugin @typescript-eslint/parser
```
Then we have to create a `eslintrc.json` file and put the following content in it.
```json
// eslintrc.json file
{
  "env": {
    "browser": true,
    "es6": true
  },
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended"
  ],
  "globals": {
    "Atomics": "readonly",
    "SharedArrayBuffer": "readonly",
    "React": "writable"
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "plugins": ["react", "@typescript-eslint"],
  "rules": {
    "react/react-in-jsx-scope": "off"
  }
}
```

## Setting up Jest for Testing
Now it's time to set up the testing framework [Jest](https://jestjs.io/en/). Jest works pretty well with React and Next. First, install Jest as a `devDependency`.
```shell
npm i -D jest ts-jest babel-jest react-test-renderer @types/jest @testing-library/react @testing-library/jest-dom
```
Now, we create a `.babelrc` file with the following:
```
# .babelrc file
{
    "presets": ["next/babel"]
}
```
Then we shall create a `jest.config.js` file with the following content:
```javascript
// jest.config.js file
module.exports = {
    collectCoverageFrom: [
      "**/*.{js,jsx,ts,tsx}",
      "!**/*.d.ts",
      "!**/node_modules/**",
    ],
    setupFilesAfterEnv: ["<rootDir>/setupTests.js"],
    testPathIgnorePatterns: ["/node_modules/", "/.next/"],
    transform: {
      "^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
    },
    transformIgnorePatterns: [
      "/node_modules/",
      "^.+\\.module\\.(css|sass|scss)$",
    ],
    moduleNameMapper: {
      "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",
    },
    //additional prop from a github issue: https://github.com/zeit/next.js/issues/8663
    preset: "ts-jest",
    testEnvironment: "jsdom",
    globals: {
      // we must specify a custom tsconfig for tests because we need the typescript transform
      // to transform jsx into js rather than leaving it jsx such as the next build requires.  you
      // can see this setting in tsconfig.jest.json -> "jsx": "react"
      "ts-jest": {
        tsConfig: "tsconfig.jest.json",
      },
    },
  }
```
After that, we have to create a `tsconfig.jest.json` file like the following:
```json
// tsconfig.jest.json
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
      "jsx": "react"
    }
}
```
Now, we have to create a `setupTests.js` file like the following:
```javascript
/*
 * setupTests.js file
 */
// optional: configure or set up a testing framework before each test
// if you delete this file, remove `setupFilesAfterEnv` from `jest.config.js`

// used for __tests__/testing-library.js
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom/extend-expect'
```
The last file we need to create for Jest is a `cssTransform.js` in the `config/jest` directory. 
```javascript
/*
 * cssTransform.js file
 */
module.exports = {
    process() {
      return 'module.exports = {};'
    },
    getCacheKey() {
      return 'cssTransform'
    },
}
```
Then finally in our `package.json` file, we have to add the following two scripts.
```json
// package.json file
{
  ...,
  "scripts": {
    ...,
    "test": "jest --watch",
    "test:ci": "jest --ci"
  },
  ...
}
```
The Jest framework is set up now. We will add a simple test now. For this, we will create a small component and test if that component renders without any error. Here I used the `Avatar` component which simply shows an avatar image. My `src/components/avatar.tsx` file looks like the following:
```javascript
// src/components/avatar.tsx file
function Avatar() {
    return (
        <div className="avatar">
            <img src="/avatar.png" alt=""/>
        </div>
    )
}

export default Avatar
```
We will render this component in our `Index` page which is the `src/pages/index.tsx` file. To test this component let us create a `src/components/__tests__/avatar.test.tsx` file.
```javascript
// src/components/__tests__/avatar.test.tsx file
import React from "react"
import Avatar from "../avatar"
import TestRenderer from "react-test-renderer"
import { cleanup } from "@testing-library/react"

afterEach(cleanup);

describe('Avatar', () => {
    it('should render without throwing an error', () => {
        const testRenderer = TestRenderer.create(<Avatar />);
        expect(testRenderer.toJSON()).toMatchSnapshot();
    });
})
```
To run the test use
```shell
npm run test
```

## Setting up TailwindCSS
[TailwindCSS](https://tailwindcss.com/) is a utility-first CSS framework and it works well with React and Next. We will add Tailwind as a PostCSS plugin to our project. To install TailwindCSS and PostCSS:
```shell
npm i -D tailwindcss postcss-preset-env postcss-flexbugs-fixes
```
Now, we have to create a `tailwind.config.js` file and a `postcss.config.js` file in our project root.
```javascript
// tailwind.config.js file
module.exports = {
  future: {
    removeDeprecatedGapUtilities: true,
  },
  purge: ['./src/components/**/*.{js,ts,jsx,tsx}', './src/pages/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        'accent-1': '#333',
      },
    },
  },
  variants: {},
  plugins: [],
}
```
```javascript
// postcss.config.js file
module.exports = {
  plugins: [
    'tailwindcss',
    'postcss-flexbugs-fixes',
    [
      'postcss-preset-env',
      {
        autoprefixer: {
          flexbox: 'no-2009',
        },
        stage: 3,
        features: {
          'custom-properties': false,
        },
      },
    ],
  ],
}
```
Now replace everything from your `src/styles/globals.css` with the following:
```css
@tailwind base;

/* Write your own custom base styles here */

/* Start purging... */
@tailwind components;
/* Stop purging. */

/* Write you own custom component styles here */

/* Start purging... */
@tailwind utilities;
/* Stop purging. */
```
Now, import this `globals.css` file in your `src/pages/_app.tsx` file like:
```javascript
// src/pages/app.tsx file
import '../styles/globals.css'
```
We are all set up now and ready to start building our Next.js application. One final thing I want to do is to add some Tailwind utility classes to our page. Here is our `src/pages/index.tsx`
```javascript
// src/pages/index.tsx

import Head from 'next/head'
import Avatar from '../components/avatar'

export default function Home() {
  return (
    <div className="flex h-screen items-center justify-center">
      <Head>
        <title>My Next App</title>
      </Head>
      <Avatar />
    </div>
  )
}
```
Finally, we are done setting up everything and testing that they are all working properly. Now, you can start building your awesome Next.js app on top of this boilerplate. You can also find the project boilerplate on [Github](https://github.com/shuv1824/nextjs-starter). Hope this will help you get started with Next.js quickly. Happy coding.