Next.js Tips
source link: https://nextjstips.com
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
The website is maintained by Erhan Karadeniz.
Next.js has built in type support. For getStaticProps, getStaticPaths, and getServerSideProps, you can use the GetStaticProps, GetStaticPaths, and GetServerSideProps types respectively. API routes has also type support. #typescript #javascript
- Snippet
- Image
import { GetStaticProps, GetStaticPaths, GetServerSideProps, NextApiRequest, NextApiResponse } from 'next'
export const getStaticProps: GetStaticProps = async context => {
// ...
}
export const getStaticPaths: GetStaticPaths = async () => {
// ...
}
export const getServerSideProps: GetServerSideProps = async context => {
// ...
}
export default (req: NextApiRequest, res: NextApiResponse) => {
// ...
}
Next.js includes the next/babel preset to your app. You can extend the default config. To start, you only need to define a .babelrc file at the top of your app. This file is now the source of "truth". #javascript #reactjs #webdevelopment
- Snippet
- Image
// .babelrc
{
"presets": [
[
"next/babel",
{
"preset-env": {},
"transform-runtime": {},
"styled-jsx": {},
"class-properties": {}
}
]
],
"plugins": []
}
A zone is a single deployment of a Next.js app. You can have multiple zones and merge them as a single app. With multi zones support, you can merge multiple apps into a single one. #javascript #reactjs
- Snippet
- Image
// now.json
{
"version": 2,
"builds": [
{ "src": "blog/package.json", "use": "@now/next" },
{ "src": "home/package.json", "use": "@now/next" }
],
"routes": [
{ "src": "/blog/_next(.*)", "dest": "blog/_next$1" },
{ "src": "/blog(.*)", "dest": "blog/blog$1" },
{ "src": "(.*)", "dest": "home$1" }
]
}
Next.js provides an integrated #TypeScript experience out of the box. To get started, create an empty tsconfig.json file in the root of your project. Then, run next and #Nextjs will guide you through the installation of the required packages to finish the setup. #reactjs #webdev
- Snippet
- Image
npm run dev
# You'll see instructions like these:
#
# Please install typescript, @types/react, and @types/node by running:
#
# yarn add --dev typescript @types/react @types/node
#
# ...
Next.js allows you to configure the target browsers (for Autoprefixer and compiled #css features) through Browserslist. To customize browserslist, create a browserslist key in your package.json. #javascript #reactjs
- Snippet
- Image
// package.json
{
"browserslist": [">0.3%", "not ie 11", "not dead", "not op_mini all"]
}
In order to extend our usage of webpack in #NextJS, you can define a function that extends its config inside next.config.js. The webpack function is executed twice, once for the server and once for the client. #javascript #reactjs #programming
- Snippet
- Image
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Note: we provide webpack above so you should not `require` it
// Perform customizations to webpack config
// Important: return the modified config
config.plugins.push(new webpack.IgnorePlugin(/\/__tests__\//))
return config
},
webpackDevMiddleware: config => {
// Perform customizations to webpack dev middleware config
// Important: return the modified config
return config
},
}
If you want to render the built-in error page you can by importing the Error component. The Error component also takes title as a property if you want to pass in a text message along with a statusCode. #javascript #webdev
- Snippet
- Image
import Error from 'next/error'
import fetch from 'node-fetch'
export async function getServerSideProps() {
const res = await fetch('https://api.github.com/repos/zeit/next.js')
const errorCode = res.ok ? false : res.statusCode
const json = await res.json()
return {
props: { errorCode, stars: json.stargazers_count },
}
}
export default function Page({ errorCode, stars }) {
if (errorCode) {
return <Error statusCode={errorCode} />
}
return <div>Next stars: {stars}</div>
}
With #Nextjs 9.3 built-in #SASS support was added. Now it’s possible to configure the compiler. For example you can now configure `includePaths`. This is possible by using the `sassOptions` key in `next.config.js`. #javascript #development #css
- Snippet
- Image
const path = require('path')
module.exports = {
sassOptions: {
includePaths: [path.join(__dirname, 'styles')]
}
}
With #Nextjs 9.4 React Fast Refresh is introduced. Fast Refresh is a new hot reloading experience that gives you instantaneous feedback on edits made to your React components. Make sure you have no class components or unnamed default exports. #javascript #programming #reactjs
- Snippet
- Image
/*
* Fast Refresh is a new hot reloading experience that gives you instantaneous feedback on edits made to * your React components.
*/
// This will not get optimal results.
// pages/index.js
export default (props) => {
return <MyComponent />
}
// This will give better results.
const Home = (props) => {
return <MyComponent />
}
export default Home
#Nextjs 9.4 has better support for absolute imports and aliases. It is now possible to set a baseurl in jsconfig.js. This file also has support for paths now. #javascript #webdev #tip
- Snippet
- Image
// jsconfig.json or tsconfig.json
{
"compilerOptions": {
"baseUrl": "."
}
}
// Without baseUrl
import Button from '../../../../components/button'
// With baseUrl option set
import Button from 'components/button'
// tsconfig.json or jsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/design-system/*": ["components/design-system/*"]
}
}
}
// Imports 'components/design-system/button'
import Button from '@/design-system/button'
Last week the #Google #Chrome team introduced Core Web Vitals. These are quality signals key to delivering great UX. #Nextjs 9.4 introduced `reportWebVitals`. Now you can send metrics directly to the chrome extension. #javascript #webdev
- Snippet
- Image
// pages/_app.js
// Will be called once for every metric that has to be reported.
export function reportWebVitals(metric) {
// These metrics can be sent to any analytics service
console.log(metric)
}
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
A common pain point of devs using Next.js was working with env vars. In #Nextjs 9.4 this process is more streamlined. You prefix your env variable with `NEXT_PUBLIC_` to expose it to the browser. No need for `next.config.js` to expose and .env files are loaded by default now
- Snippet
- Image
// pages/index.js
// The environment variable will be exposed to the browser
console.log('My Application Version', process.env.NEXT_PUBLIC_VERSION)
export default function HomePage() {
return <h1>Hello World</h1>
}
Incremental Static Regeneration (beta) has landed with #Nextjs 9.4. This is a mechanism to update existing pages, by re-rendering them in the background as traffic comes in. Inspired by SWR, this ensures traffic is served uninterrupted, always statically. #javascript
- Snippet
- Image
export async function getStaticProps() {
return {
props: await getDataFromCMS(),
// Next.js will attempt to re-generate the page:
// - when a request comes in
// - at most once every second
unstable_revalidate: 1
}
}
500 errors are handled both client-side and server-side by the Error component. If you wish to override it, define the file pages/_error.js and add the following code. #javascript #webdev #frontend
- Snippet
- Image
// pages/_error.js
function Error({ statusCode }) {
return (
<p>
{statusCode
? `An error ${statusCode} occurred on server`
: 'An error occurred on client'}
</p>
)
}
Error.getInitialProps = ({ res, err }) => {
const statusCode = res ? res.statusCode : err ? err.statusCode : 404
return { statusCode }
}
export default Error
You can create a custom 404 page for your Next.js application. To create a custom 404 page you can create a pages/404.js file. This file is statically generated at build time. #javascript #webdev
- Snippet
- Image
// pages/404.js
export default function Custom404() {
return <h1>404 - Page Not Found</h1>
}
Did you know that Next.js has support for AMP pages? You can even run and hybrid AMP page. The snippet shows a page rendered as traditional HTML (default) and AMP HTML (by adding ?amp=1 to the URL) #javascript #webdevelopment
- Snippet
- Image
import { useAmp } from 'next/amp'
export const config = { amp: 'hybrid' }
function About(props) {
const isAmp = useAmp()
return (
<div>
<h3>My AMP About Page!</h3>
{isAmp ? (
<amp-img
width="300"
height="300"
src="/my-img.jpg"
alt="a cool image"
layout="responsive"
/>
) : (
<img width="300" height="300" src="/my-img.jpg" alt="a cool image" />
)}
</div>
)
}
export default About
`next export` exports your app to static HTML, which can be run standalone without the need of a Node.js server. The exported app supports almost every feature of Next.js, incl. dynamic routes, prefetching, preloading and dynamic imports. #javascript
- Snippet
- Image
// Package.json
"scripts": {
"build": "next build && next export"
}
/*
Afterwards from your commandline
npm run build
or use
next build && next export
directly from your commandline
*/
Static Generation is useful when your pages fetch data from a headless CMS. However, it’s not ideal when you’re writing a draft on your headless CMS and want to preview the draft immediately on your page. Luckily #nextjs supports this!
- Snippet
- Image
// pages/api/previews.js
export default async (req, res) => {
// Check the secret and next parameters
// This secret should only be known to this API route and the CMS
if (req.query.secret !== 'MY_SECRET_TOKEN' || !req.query.slug) {
return res.status(401).json({ message: 'Invalid token' })
}
// Fetch the headless CMS to check if the provided `slug` exists
// getPostBySlug would implement the required fetching logic to the headless CMS
const post = await getPostBySlug(req.query.slug)
// If the slug doesn't exist prevent preview mode from being enabled
if (!post) {
return res.status(401).json({ message: 'Invalid slug' })
}
// Enable Preview Mode by setting the cookies
res.setPreviewData({})
// Redirect to the path from the fetched post
// We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
res.writeHead(307, { Location: post.slug })
res.end()
}
When doing shallowing routing, your URL will change but data fetching methods won’t be called. Keep in mind that this only works for same page URL changes! #javascript
- Snippet
- Image
import { useEffect } from 'react'
import { useRouter } from 'next/router'
// Current URL is '/'
function Page() {
const router = useRouter()
useEffect(() => {
// Always do navigations after the first render
router.push('/?counter=10', undefined, { shallow: true })
}, [])
useEffect(() => {
// The counter changed!
}, [router.query.counter])
}
export default Page
Next.js can serve static files, like images, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/). This folder is also useful for robots.txt, Google Site Verification etc.
- Snippet
- Image
function MyImage() {
return <img src="/my-image.png" alt="my image" />
}
export default MyImage
Component-level #CSS in in Next.js is an optional feature. You can create a file called button.module.css, import this in you button.js file. In production, all CSS Module files will be automatically concatenated into many minified and code-split .css files.
- Snippet
- Image
import styles from './Button.module.css'
export function Button() {
return (
<button
type="button"
// Note how the "error" class is accessed as a property on the imported
// `styles` object.
className={styles.error}
>
Destroy
</button>
)
}
Did you know Next.js has built-in #CSS support? It’s as simple as importing a global stylesheet in your _app.{js/tsx}. Don’t import your css in an other file, since this is not supported. You can do that with component-level CSS. #javascript #typescript
- Snippet
- Image
import '../styles.css'
// This default export is required in a new `pages/_app.js` file.
export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
Fetching data on the client side? Use https://swr.now.sh/ by @zeithq. It handles caching, revalidation, focus tracking, refetching on interval, and more.
- Snippet
- Image
import useSWR from 'swr'
function Profile() {
const { data, error } = useSWR('/api/user', fetch)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
If you export an async function called getServerSideProps from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps.
- Snippet
- Image
export async function getServerSideProps(context) {
return {
props: {}, // will be passed to the page component as props
}
}
// The context parameter is an object containing the following keys:
// params: If this page uses a dynamic route, params contains the route parameters. If the page name is [id].js , then params will look like { id: ... }.
// req: The HTTP IncomingMessage object.
// res: The HTTP response object.
// query: The query string.
// preview: preview is true if the page is in the preview mode and false otherwise.
// previewData: The preview data set by setPreviewData.
Files can be read directly from the filesystem in getStaticProps with `process.cwd()`. In order to do so you have to get the full path to a file.
- Snippet
- Image
// This function gets called at build time on server-side.
// It won't be called on client-side.
export async function getStaticProps() {
const postsDirectory = path.join(process.cwd(), 'posts')
const filenames = fs.readdirSync(postsDirectory)
const posts = filenames.map(filename => {
const filePath = path.join(postsDirectory, filename)
const fileContents = fs.readFileSync(filePath, 'utf8')
// Generally you would parse/transform the contents
// For example you can transform markdown to HTML here
return {
filename,
content: fileContents,
}
})
// By returning { props: posts }, the Blog component
// will receive `posts` as a prop at build time
return {
props: {
posts,
},
}
}
You can generate static pages (SSG) with dynamic routes. You'll have to use the built in functions getStaticPaths() & getStaticProps(). #javascript #JamStack
- Snippet
- Image
import Layout from '../../components/layout'
export default function Post() {
return <Layout>...</Layout>
}
export async function getStaticPaths() {
// Return a list of possible value for id
}
export async function getStaticProps({ params}) {
// Fetch necessary data for the blog post using params.id
}
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK