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.