Categories
JavaScript Next.js React

How to Set Up ESLint and Prettier in React or Next.js Projects and Format Code Automatically with Prettier with VS Code?

ESLint lets us catch errors and bad practices in our React or Next.js project easily.

And Prettier lets us format our code automatically by following some rules that are defined.

In this article, we’ll look at how to set up ESLint and Prettier in our React or Next.js project and format code automatically on save with Prettier in VS Code.

Getting Started

To get started, we’ve to install a few packages into our React or Next.js project.

To install all of them, we run:

npm i -D babel-eslint eslint eslint-config-airbnb eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks prettier

The -D flag will install the packages as dev dependencies.

Then in VS Code, we install the ESLint and Prettier extensions.

The easiest way to do this is to press Ctrl+Shift+P, and then search for ‘install extensions’ in the command search box.

Then enter the name of the extensions into the Extensions pane on the left.

Now we can configure ESLint and Prettier to search for issues and format our code.

Configure ESLint

To configure ESLint, we can add an .eslintrc.json file on the root of the project folder and add:

{
  "root": true,
  "parser": "babel-eslint",
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:react-hooks/recommended",
    "airbnb-base",
    "airbnb-base/rules/strict",
    "airbnb/rules/react",
    "plugin:prettier/recommended"
  ],
  "env": {
    "browser": true,
    "commonjs": true,
    "es6": true,
    "node": true
  },
  "parserOptions": {
    "ecmaVersion": 2021,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true
    }
  },
  "settings": {
    "react": {
      "version": "detect"
    }
  },
  "plugins": [],
  "rules": {
    "react/react-in-jsx-scope": "off",
    "react/jsx-props-no-spreading": "off",
    "react/jsx-filename-extension": [
      1,
      {
        "extensions": [
          ".js",
          ".jsx"
        ]
      }
    ],
    "prettier/prettier": [
      "error",
      {},
      {
        "usePrettierrc": true
      }
    ]
  }
}

We extend the rules set we want ESLint to check in the extends section.

And in the rules section, we configure or turn off some rules.

'off' turns them off.

The rest of the rules are set to their default values.

ecmaVersion is set to 2021 to check the latest JavaScript syntax as of 2021.

Configure Prettier

To configure Prettier, we create a .prettierc file in the project folder root and add:

{
  "semi": true,
  "tabWidth": 2,
  "printWidth": 100,
  "trailingComma": "all",
  "jsxBracketSameLine": true
}

We add some rules to make Prettier format the code the way we want.

printWidth sets the max line width.

trailingComma lets Prettier add trailing commas to places where they’re allowed.

semi adds semicolons to places that should have them like end of lines.

tabWidth sets the width of the tabs in terms of spaces. 2 means 2 spaces for tabs.

jsxBracketSameLine puts the closing bracket of a multiline JSX element at the end of the last line instead of on the next line.

Also, we need to make sure that Prettier formats the code files that we write instead of package or auto-generated files.

To do this, we add a .prettierignore file to the project folder root and write:

.next
node_modules
.vscode
package.json
package-lock.json
dist

.next is the Next.js specific folder with the built files.

dist has the built files.

.vscode has VS code settings for the workspace.

Configure VS Code to Format Files on Save with Prettier and Autofix ESLint Issues

To format code with Prettier and fix ESLint issues that can be automatically fixed, we add the following to .vscode/settings.json :

{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "editor.formatOnSave": true,
  "eslint.alwaysShowStatus": true
}

We can set the default formatter to Prettier by pressing Ctrl+Shift+P, then search for ‘Format Document With’, press Enter, then select ‘Configure Default Formatter’, then we can select Prettier.

Conclusion

We can fix many code issues in React and Next,js projects and make our code neater with ESLint and Prettier.

Categories
Next.js

Next.js — Dynamic Imports and Static Pages

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at dynamic imports and render static pages with Next.js.

Dynamic Import

ES2020 supports dynamic imports natively.

We can use this within our Next.js to dynamically import our components.

It also works with server-side rendering.

This lets us split our code into manageable chunks.

For example, we can write:

components/name.js

function Name() {
  return (
    <span>world</span>
  )
}

export default Name

pages/hello.js

import dynamic from 'next/dynamic'

const NameComponent = dynamic(() => import('../components/name'))

function Hello() {
  return (
    <div>hello <NameComponent /></div>
  )
}

export default Hello

We imported the dynamic function and passed in a callback that calls import to import the component.

Then we can use the NameComponent in our code.

Now we should see:

hello world

displayed.

Dynamic Component With Named Exports

We can create dynamic components with named exports.

To do that, we can write:

components/name.js

export function Name({ }) {
  return (
    <span>world</span>
  )
}

pages/hello.js

import dynamic from 'next/dynamic'

const NameComponent = dynamic(() => import('../components/Name').then((mod) => mod.Name)
)

function Hello() {
  return (
    <div>hello <NameComponent /></div>
  )
}

export default Hello

In the callback, we called import with the then callback to return the Name component from the module.

With Custom Loading Component

We can also add a component to show the component when the component loads.

For example, we can write:

components/name.js

function Name() {
  return (
    <span>world</span>
  )
}
export default Name

pages/hello.js

import dynamic from 'next/dynamic'

const NameComponent = dynamic(() => import('../components/Name'), { loading: () => <p>loading</p> })

function Hello() {
  return (
    <div>hello <NameComponent /></div>
  )
}

export default Hello

We have an object with the loading property in the code with a component as the value.

Disable Server-Side Rendering

Server-side rendering can be disabled by passing in an object into the dynamic function with the ssr property set to false .

For example, we can write:

components/name.js

function Name() {
  return (
    <span>world</span>
  )
}
export default Name

pages/hello.js

import dynamic from 'next/dynamic'

const NameComponent = dynamic(() => import('../components/Name'), { ssr: false }
)

function Hello() {
  return (
    <div>hello <NameComponent /></div>
  )
}

export default Hello

Static HTML Export

We can export our app to static HTML with the next export command.

It works by prerendering all the pages to HTML.

The pages can export a getStaticPaths property that returns all the paths that we want to prerender.

next export should be used when there are no dynamic data changes in our app.

To use it, we run:

next build && next export

next build builds the app and next export gets us the HTML pages.

We can also add both commands to our package.json file:

"scripts": {
  "build": "next build && next export"
}

and run npm run build to run it.

getInitialProps can’t be used with getStaticProps or getStaticPaths on any page.

Conclusion

We can dynamically import components with Next.js.

Also, we can build our Next.js app to static HTML files.

Categories
Next.js

Next.js — Middlewares and Preview Mode

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at route middlewares and preview mode with Next.js.

Connect/Express Middleware Support

We can use Connect compatible middleware.

For example, we can add the cors middleware by installing it and adding to our Next.js app.

To install it, we run:

npm i cors

or

yarn add cors

Then we can add it to our API route by writing:

import Cors from 'cors'

const cors = Cors({
  methods: ['GET', 'HEAD'],
})

function runMiddleware(req, res, fn) {
  return new Promise((resolve, reject) => {
    fn(req, res, (result) => {
      if (result instanceof Error) {
        return reject(result)
      }
      return resolve(result)
    })
  })
}

async function handler(req, res) {
  await runMiddleware(req, res, cors)
  res.json({ message: 'hello world' })
}

export default handler

We imported the Cors function.

Then we use it to create the cors middleware.

We can specify the request methods that can be used with the route.

The runMiddleware function runs the middleware by calling the fn middleware function and then resolve to the result if it’s successful.

Otherwise, the promise is rejected.

The handler is the route handler that runs the middleware and then returns the response.

Response Helpers

Next.js comes with various response helpers.

The res.status(code) method lets us set the status code of the response.

code is an HTTP status code.

res.json(json) method lets us send a JSON response.

json is a valid JSON object.

res.send(body) lets us send an HTTP response, where body is a string, object, or buffer.

res.redirect takes an optional status and path to let us redirects to a specific path or URL.

The default value of status is 307.

For example, we can call them by writing:

export default (req, res) => {
  res.status(200).json({ name: 'hello' })
}

They can be chained together.

Preview Mode

We can preview routes that are statically generated.

Next.js has a preview mode feature to solve the problem.

It’ll render the pages at request time instead of build time and fetch the draft content instead of the published content.

To use it, we call the res.setPreviewData method to do the preview.

For example, we can write:

export default (req, res) => {
  res.setPreviewData({})
  res.end('Preview mode')
}

to enable it.

Securely Accessing Data

We can access data by writing from the preview route and send to our page.

To do this, we create our preview API route by creating the pages/api/preview.js file:

export default async (req, res) => {
  const response = await fetch(`https://yesno.wtf/api`)
  const data = await response.json();
  res.setPreviewData(data)
  res.redirect('/post')
}

We get the data from an API and call setPreviewData so that we can get it from the getStaticProps function in our page JavaScript file.

Then we redirect to our file so that we can see the data on our page.

In pages/post.js , we write:

function Post({ data }) {
  return (
    <div>{data && data.answer}</div>
  )
}

export async function getStaticProps(context) {
  if (context.preview) {
    return {
      props: {
        data: context.previewData
      }
    }
  }
  return { props: { data: { answer: 'not preview' } } }
}

export default Post

We check is preview mode is on by checking the context.preview property.

If it’s true , then we get the preview data from context.previewData .

And then we display the data in our Post component.

Conclusion

We can add preview mode with Next.js so that we can view the output before it goes live.

Also, we can use Connect or Express middleware in our Next.js apps.

Categories
Next.js

Next.js — Dynamic API Routes and Middlewares

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at dynamic API routing and middleware with Next.js.

Dynamic API Routes

We can create dynamic API routes by following the usual file naming convention.

In the pages/api folder, we can create a file with a name that’s surrounded with brackets.

For example, we can create a pages/api/post/[pid].js and write:

export default (req, res) => {
  const {
    query: { pid },
  } = req
  res.end(`Post: ${pid}`)
}

Then we can make a request by going to http://localhost:3000/api/post/foo.

And we’ll get Post: foo displayed as a result.

We can set up our routes with common REST patterns.

For example, we can use GET api/posts/ to get a list of posts.

And GET api/posts/1 gets a single post.

Catch-All API Routes

We can create a catch all API route by using ... in the file name.

For example, we can create the pages/api/post/[...slugs].js file and write:

export default (req, res) => {
  const {
    query: { slugs },
  } = req
  res.end(`Post: ${slugs.join(', ')}`)
}

Then when we go to http://localhost:3000/api/post/foo/bar, we get:

Post: foo, bar

returned.

Optional Catch-all API Routes

Also, we can create catch-all API routes that don’t always expect URL parameters to be passed in.

To do that, we wrap our file name with 2 square brackets around its name.

So we can create a file called pages/api/post/[[...slugs]].js and add:

export default (req, res) => {
  const {
    query: { slugs },
  } = req
  res.end(`Post: ${Array.isArray(slugs) && slugs.join(', ')}`)
}

We have a file with its name wrapped with a square brackets.

In the code, we check if slugs is an array and then return the array entries joined together.

API Middlewares

API roiutes provide built in middleware to parse incoming requests.

They include:

  • req.cookies to parse cookies
  • req.query to parse query strings
  • req.body to parse request bodies.

Custom Config

Every API route can export a config object to change default configs.

For example, we can write:

export default (req, res) => {
  res.end(`Post: ${req.body}`)
}

export const config = {
  api: {
    bodyParser: {
      sizeLimit: '1mb',
    },
  },
}

to create an API route with a size limit imposed on the request body.

Also, we can disable body parsing with:

export default (req, res) => {
  res.end(`Post: ${req.body}`)
}

export const config = {
  api: {
    bodyParser: false,
  },
}

We set bodyParser to false to disable the body parser.

The externalResolver property is a flag that tells the server that the route is being handled by an external resolver.

It’ll disable warnings for unresolved requests.

We can use it by writing:

export default (req, res) => {
  res.end(`Post: ${req.body}`)
}

export const config = {
  api: {
    externalResolver: true,
  },
}

Conclusion

We can add dynamic routes and route middleware with Next.js.

Categories
Next.js

Next.js — Styling Components

We can create server-side rendered React apps and static sites easily Next.js.

In this article, we’ll take a look at how to style pages with Next.js.

Built-In CSS Support

Next.js lets us import CSS from JavaScript files.

It extends import beyond the basic JavaScript usage to let us import CSS files.

We can add a global stylesheet to our project.

To do this, we just create a CSS file and import it to pages/_app.js .

So we can write:

body {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

in styles.css .

Then in pages/_app.js , we write:

import '../styles/globals.css'
import './styles.css'

function MyApp({ Component, pageProps }) {
  return <Component {...pageProps} />
}

export default MyApp

We added the styles.css import.

The rest of the code is generated when we created the project.

If we want to import from the node_modules folder, then we must do so inside pages/_app.js .

Adding Component-Level CSS

We can add component-level CSS in addition to global CSS.

To do this, we follow the naming convention of [name].module.css , where [name] is the component’s file name.

For example, given that we have pages/yesno.js :

function YesNo({ data }) {
  return <p>{data.answer}</p>
}

export async function getServerSideProps() {
  const res = await fetch(`https://yesno.wtf/api`)
  const data = await res.json()
  return { props: { data } }
}

export default YesNo

We can create a file called yesno.module.js with:

.yesno {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

and then we can import it into yesno.js :

import styles from './yesno.module.css';

function YesNo({ data }) {
  return <p className={styles.yesno}>{data.answer}</p>
}

export async function getServerSideProps() {
  const res = await fetch(`https://yesno.wtf/api`)
  const data = await res.json()
  return { props: { data } }
}

export default YesNo

The yesno class in CSS is converted into the yesno property when we import it.

We use it to populate the className prop to set the class names of the elements.

CSS modules are an optional features and it’s only enabled for files with the .module.css extension.

This means we need the .module part of the file name if we want to import them as we did.

We can also use link tags as always to add our CSS files.

CSS modules are automatically concatenated and minified and code-split.

Sass Support

Next.js lets us import SASS files with the .scss and .sass extensions.

We can also use them as CSS modiles with the .module.scss and .module.sass extensions.

To use SASS in our Next.js app, we’ve install the sass package by running:

npm install sass

The SCSS syntax is an extension of the CSS syntax, SASS has an indentation syntax that’s different from CSS.

Therefore, it’s easier to work with SCSS files.

Customizing Sass Options

We can change the paths of the style files to include within the next.config.js file.

For example, we can write:

const path = require('path')

module.exports = {
  sassOptions: {
    includePaths: [path.join(__dirname, 'styles')],
  },
}

to change the path of the style files we want to include.

Conclusion

We can style our Next.js app with CSS and SASS / SCSS.