My NextJS Setup

My NextJS Setup

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

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 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:

/* 
 * _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 comes in. To setup ESLint in your Next.js application install ESLint as a devDependency

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.

// 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. Jest works pretty well with React and Next. First, install Jest as a devDependency.

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:

// 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:

// tsconfig.jest.json
{
    "extends": "./tsconfig.json",
    "compilerOptions": {
      "jsx": "react"
    }
}

Now, we have to create a setupTests.js file like the following:

/*
 * 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.

/*
 * 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.

// 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:

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

// 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

npm run test

Setting up TailwindCSS

TailwindCSS 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:

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.

// 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: [],
}
// 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:

@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:

// 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

// 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. Hope this will help you get started with Next.js quickly. Happy coding.