# NextJs (opens new window) overview

https://nextjs.org/docs/getting-started/react-essentials#server-components

https://www.patterns.dev/posts/islands-architecture

⚡️ Tags: 📍Framework

# Abbreviation

  • CSR: Client Site Rendering
  • SSR: Server Site Rendering
  • SSG: Static Site Generation
  • ISR: Incremental Static Regeneration
  • ASO: Automatic Static Optimization

# Rendering

Name Description
Static automatically rendered as static HTML (uses no initial props)
SSG automatically generated as static HTML + JSON (uses getStaticProps)
ISR incremental static regeneration (uses revalidate in getStaticProps)
SSG + CSR pre-rendered HTML + data fetching on client side using useEffect
SSR server-side renders at runtime (uses getInitialProps or getServerSideProps)

# Pre-rendering

Stage Using NextJs Using Plain ReactJs
Initial Load Pre-rendered HTML is displayed App is not rendered
Hydration App becomes interactive App becomes interactive

# SSG - Static Site Generation

The HTML is generated at build-time and is reused for each request.

getStaticProps

  • Should export from a Page.
  • Can't use with getServerSideProps()
  • Only run on build time (server side)
  • Run on every request in dev mode
interface Post {
  id: string;
  title: string;
}
interface PageProps {
  post: Post;
}
export default function PostDetailPage({ post }: PageProps) {
  const router = useRouter();
  return (
    <div>
      <h1>Post Page</h1>
      <p>{post.id}</p>
      <p>{post.title}</p>
    </div>
  );
}

export const getStaticProps: GetStaticProps<PageProps> = async () => {
  await new Promise((resolve) => setTimeout(resolve, 5000));
  return {
    props: {
      post: {
        id: "123-abc",
        title: "Learn NextJS",
      },
    },
  };
};

# SSR - Server Side Rendering

The HTML is generated on each request.

# CSR - Client Side Rendering

Static Generation without Data + Fetch Data on the Client-side

import dynamic from "next/dynamic";

const DynamicComponentWithNoSSR = dynamic(
  () => import("../components/hello3"),
  { ssr: false }
);

function Home() {
  return (
    <div>
      <Header />
      <DynamicComponentWithNoSSR />
      <p>HOME PAGE is here!</p>
    </div>
  );
}
export default Home;

Read more about Dynamic Import (opens new window)

# ISR - Incremental Static Regeneration

Static pages can be generated at runtime (on-demand) instead of at build-time with ISR.

Readmore (opens new window)

# ASO - Automatic Static Optimization

Next.js automatically determines that a page is static (can be prerendered) if it has no blocking data requirements. This determination is made by the absence of getServerSideProps and getInitialProps in the page.

. ASO Not ASO (getServerSideProps)
router.query empty when pre-rendering, update after hydration always available
next build output an HTML output an JS file

# File-system Routing

└── pages/
    ├── index.tsx                 -- Index route. E.g: example.com/
    ├── about.tsx                 -- Nested route. example.com/about
    ├── posts/
    │   ├── create.tsx            -- Nested route. Pre-defined route.
    │   ├── [postId].tsx          -- Dynamic route. Single param
    │   └── [[...slug]].tsx       -- Dynamic route. Catch all
    └── categories/
        ├── [categoryId]/
        │   └── posts/
        │       └── [postId].tsx   -- Dynamic route. Multiple params.
        └── [...slug].tsx        -- Dynamic route. Optional catch all (/)

When a file is added to the pages directory it's automatically available as a route. There are three kind of routes:

  • Index routes: file named index
  • Nested routes: nested folder in pages
  • Dynamic routes: brackets in file name to match parameter dynamically

Route match order

  • Pre-defined routes. E.g: pages/posts/create.tsx
  • Dynamic routes. E.g: pages/posts/[postId].tsx
  • Catch all routes. E.g: pages/posts/[...slug].tsx

Dyanmic routes:

Name File URL router.query
Single param pages/posts/[postId].tsx /posts/123 { postId: '123' }
Multiple params pages/categories/[categoryId]/posts/[postId].tsx /categories/frontend/posts/js { categoryId: 'frontend', postId: 'js' }
Catch all pages/posts/[...slug].tsx /posts/easy/frontend { slug: ['easy', 'frontend'] }
Optional catch all pages/posts/[[...slug]].tsx /posts/ {}
import Link from 'next/link'
function HomePage() {
  return (
    <Link href="/about">
        <a>About Us</a>
    </Link>
  )
}

Link props Full here (opens new window)

Name Default Description
href
passHref false Forces Link to send the href prop to its child
prefetch true Prefetch the page in background
replace false Replace the current history state instead of adding a new url into the stack
scroll true Scroll to the top of the page after navigation
import { useRouter } from 'next/router'
function App() {
    const router = useRouter();

    function handleSubmit() {

        router.push('/success-page');

        // or using options object
        router.push({
        pathname: '/posts/[postId]',
            query: {
                postId: 123,
                ref: 'social',
            },
        })
    }
    return (...);
}

router props & methods full here (opens new window)

Name Description
pathname current route
query The query string parsed to an object
basePath The active basePath (if enabled)
locale The active locale (if enabled)
isFallback Whether the current page is in fallback mode
push() Handles client-side transitions
replace() prevent adding a new URL entry into the history stack
prefetch() Prefetch pages for faster client-side transitions
back() Navigate back in history
reload() executes window.location.reload()

Shallow Routing Shallow routing allows you to change the URL without running data fetching methods again, that includes getServerSideProps, getStaticProps, and getInitialProps.

You'll receive the updated pathname and the query via the router object (added by useRouter or withRouter), without losing state.

 useEffect(() => {
    // Always do navigations after the first render
    router.push('/?counter=10', undefined, { shallow: true })
  }, [])

# How prefetching works

https://web.dev/route-prefetching-in-nextjs/

  • Only prefetches links that appear in the viewport.
  • It use Intersection Observer API (opens new window) to detect.
  • Prefetching is only enabled in production.
  • But it will be disabled in slow network or when users have Save-Data turned on.

# Optimization

# Images (opens new window)

import Image from 'next/image'
  • use <Image /> from next/image instead of others. Read more (opens new window)
  • attributes to optimize perf priority, sizes, quality, blurDataURL
  • Nextjs automatically detect browser's supported image formats
  • fallback with onError

# Font

next/font will automatically optimize your fonts (including custom fonts) and remove external network requests for improved privacy and performance.

# Lazy Loading (opens new window)

import dynamic from 'next/dynamic'

next/dynamic is a composite of React.lazy() and Suspense.

1/ Loading lazy component

Lazyload offscreen sections is a good choice

Should not implement manually if you don’t want to face another hundred problems in React (optimize useEffect, rerender state, exceed resources, …). Read more

const PresentationMarketPlace = dynamic(() =>
  import('./PresentationMarketPlace').then((c) => c.PresentationMarketPlace)
)

const LazySection = ({ section, props }: { section: SectionInfo; props: any }) => {
  const { ref, inView } = useInView({
    triggerOnce: true,
    fallbackInView: true,
    threshold: 0.5,
  })
  return <Box ref={ref}>{inView ? createElement(PresentationMarketPlace, props) : <LogoLoading />}</Box>
}

2/ Loading External Libraries

<input
    type="text"
    placeholder="Search"
    onChange={async (e) => {
      const { value } = e.currentTarget
      // Dynamically load fuse.js
      const Fuse = (await import('fuse.js')).default
      const fuse = new Fuse(names)
      setResults(fuse.search(value))
    }}
  />

# Shallow routing

Shallow routing is a technique that allows you to update the URL of a page without reloading the page itself or fetching new data from the server. This can improve the user experience by making page transitions faster and smoother.

<Link shallow={true} />

router.push(targetUrl, { shallow: true })

Read more

# optimizePackageImports

Use @next/bundle-analyzer to analyze which included in bundled file

I figured out Nextjs using Webpack to build the script chunks.

  • In the Webpack world, there is a Tree-shaking definition, that will remove the dead code in the external package.
  • Even though Vercel says no to that concept, they have another solution that processes cheaper than Tree-shaking. Read more (opens new window)

Applied in next.config.js file

module.exports = {
  experimental: {
    optimizePackageImports: ["my-lib", "@/components", "lodash"]
  }
}

# Comparation

# ReactJs vs NextJs

ReactJS NextJS
Type Library Framework
Bootstrap create-react-app create-next-app
Rendering CSR CSR, SSR and SSG
Hosting Any kind of static server NodeJS server
Built-in SEO support ❌ NO ✅ YES
When to use Internal / Private web app, dashboard admin Marketing / Landing pages / Blog / eCommerce
Code Playground codesandbox.io codesandbox.io

# ExpressJs vs NextJs

ExpressJS NextJS
Data fetching Doesn’t let Express.js deliver a response from server-side to an EJS template in client’s side Next.js data fetching enables you to deliver your content in a variety of ways, based on the use case of your application
Server use Can be used both on the client-side and the server-side Used for building server-side rendering applications
Plug-in and ecosystem The Express Gateway plugin includes entities and supports event subscription. Next.js makes use of existing powerful tools such as Webpack, Babel, and Uglify, and presents them to the end user in a stunningly simple interface.
Static generation Deferred static generation. Developers can choose to postpone the creation of specific pages until the first time a user requests them. Incremental static generation. After you’ve built your site, you can use Next.js to create or update static pages.
Scalability When developing a large-scale web application, it handles user API calls efficiently and requires little to no extra configuration. Next, js makes it simple to scale multiple pages because it allows you to choose whether to render each page on the client, the server, or both.
Speed a Nodejs backend framework with minimalist and fast tools and functions for developing scalable backend applications Because of the static destinations and server-side rendering, it is extremely fast.
SEO It is beneficial for SEO as it offers crawlers from search engines with a fully rendered homepage, making their work easier. Next.js is a fundamental tool for achieving impressive SEO performance.

SHOULD NOT USE NEXTJS FOR BACKEND

Real world cases, most of the time, we keep FE & BE repo separated Nextjs is not optimized for horizontal scale Diff from coding styles / convention

# Other

Helper check

function isBrowser() {
    return typeof window !== 'undefined';
}

https://mobisoftinfotech.com/resources/blog/next-js-framework/