Setup using Vite
Vite is a build tool and dev server for React app.
- A front-end tool to quickly develop app/prototype, SPAs, Dashboard, interal tooling
- Minimal and any extra tech will need to be added: routing, SSR, testing setup, API routes
Basic Commands
- Creating the Project :
npm create vite@latest my-app - Select React framework, and Javascript or Typescript variant
- Running the Developer Server :
npm run devin the project root folder - Building the Project :
npm run buildin the project root folder
Folder Structure
my-vite-app/
├── index.html
├── src/
│ ├── App.jsx # root component that wraps all other components
│ ├── main.jsx # entry point of website
│ ├── pages/
│ │ ├── Home.jsx # Home page (/)
│ │ └── About.jsx # About page (/about)
│ ├── store.js
└── public/ # holds static assets
├── images/ # accessed from root (/images/*)
├── sitemap.xml # good for SEO (/sitemap.xml)
└── robots.txt # accessed from root (/robots.txt)
├── package.json
└── vite.config.jsMinimal Project + React Router
React Router is used to add routing functionality into the Vite app
- the main.jsx is the same as index.js in other React app (except Next.js)
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App.jsx';
ReactDOM.createRoot(document.getElementById('root')).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
// App.jsx
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
export default function App() {
return (
<div>
<nav>
<Link to='/'>Home</Link> |{" "}
<Link to='/about'>About</Link>
</nav>
<Routes> # Routes is the main container that swaps components out depending on the current URL
<Route path='/' element={<Home />} />
<Route path='/about' element={<About />} />
</Routes>
</div>
);
}
// pages/Home.jsx
export default function Home() {
return (
<div>
<h1>Home Page</h1>
</div>
);
}
// pages/About.jsx
export default function About() {
return <h1>About Page</h1>;
}Setup using Next.js
Next.js is a framework for full-stack React app.
- It has built-in features like routing, SSR, API routes, and testing setup (Jest)
- Good for SEO and a variety of apps like blogs, marketing sites, e-commerce, enterprise apps, SaaS and large apps
Basic Commands
- Creating the Project :
npx create-next-app@latest my-app - ESLint : Tool to make sure Javascript and Typescript codes are clean and error-free
- Turbopack: Build tool to package code efficiently for dev and production
- Running the Developer Server :
npm run devin the project root folder - Building the Project :
npm run buildin the project root folder - Testing the build :
npm run startto test the production build
Folder Structure
my-next-app/
├── app/ # the root for all navigation and links
│ ├── layout.jsx # Optional Global Layout - entry point if file exist
│ ├── page.jsx # Home page (/) - normal entry point if layout.jsx did not exist
│ ├── about/
│ │ └── page.jsx # About page (/about)
└── public/ # holds static assets
├── images/ # accessed from root (/images/*)
├── sitemap.xml # good for SEO (/sitemap.xml)
└── robots.txt # accessed from root (/robots.txt)
├── store.js
├── next.config.js
├── tsconfig.json
└── package.json- In Next.js App Router (Next 13+), your entire site structure and navigation are based on the folder and file structure inside
app/folder - The
app/andpublic/folders must stay the same. - Special files like
layout.jsandpage.jscan not be renamed and need to be in their expected locations for proper navigation - The subfolders of
app/can be organized however you want - Config files like
next.config.js,package.json,tsconfig.jsonmust be in the root - Standard Node.js rules apply. Keep
node_modules/in root; you don’t move this around. - You can create folders like
components/, hooks/, utils/, styles/, lib/, etc.anywhere as long as they're imported correctly
Minimal Project with Global Layout
Next.js already has built in routing and SSR.
app/layout.jsxacts as the entry point and root component for the app so it's similar to combiningmain.jsx+App.jsxin Vite
export const metadata = {
title: 'My Next.js App',
description: 'Minimal Next.js example with SSR and layout',
};
export default function RootLayout({ children }) {
return (
<html lang='en'>
<body>
<header>
<nav>
<a href='/'>Home</a>
<a href='/about'>About</a>
</nav>
</header>
<main>{children}</main> #{children} is where the components will be swapped
<footer></footer>
</body>
</html>
);
}
// app/page.jsx (Home Page)
export const dynamic = 'force-dynamic'; // Ensures SSR every request
export default async function HomePage() {
// Fetch some server-side data
const res = await fetch('https://jsonplaceholder.typicode.com/posts/1', {
cache: 'no-store', // Forces SSR fetch
});
const data = await res.json();
return (
<section>
<h1>Welcome to My Next.js App!</h1>
<h2>SSR Example:</h2>
<p><strong>Title:</strong> {data.title}</p>
<p><strong>Body:</strong> {data.body}</p>
</section>
);
}
// app/about/page.jsx (About Page)
export default function AboutPage() {
return <h1>About Page</h1>;
}
// next.config.js (optional but recommended)
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
};
module.exports = nextConfig;Key Files
package.json: includes the scripts and dependencies of the projecthomepage: the URL for the homepage of the sitescripts: the scripts to manage project- Sample:
"script": { "scriptName": "cmd code", }
"scripts": {
"dev": "next dev --turbopack",
"build": "next build --turbopack",
"analyze": "cross-env ANALYZE=true next build",
"start": "next start",
"lint": "eslint"
},dev : script used when starting development/testing serverbuild : script for creating a production-ready buildanalyze : script to anaylyze build bundle*.config.js : configuration file for the tool you're using (Vite or Next)next.config.mjs : Next.js project configuration file to control development/production build by adding key-value pairs to the nextConfig objectbasePath: to adjust the URL of of navigation links; used when deploying app under a sub-path of a domainassetsPrefix: to adjust the URL of the Javascript and CSS files that loads from_next/folder like_next/static/assetsPrefixdoes NOT affect files in thepublic/folder- Reference: nextjs.org/docs/app/api-reference/config/next-config-js
app/not-found.js : the page that is shown for 404 error- Use
notFound()fromimport { notFound } from "next/navigation";to throw a 404 error for testing
Dynamic Vs Static Sites
- Dynamic Site Features
- Server Side Rendering (SSR)
- API Routes
- Dynamic Routing
- Authenticatoion/Sessions : can use cookies, JWTs, or OAuth flows
- Use cases: E-commerce, dashboards, social media feeds, requires authentication
- Static Site Features
- Pre-rendered HTML : fast rendering
- Works on Static Host
- Dynamic Routing
- Use cases: Blogs, docs, marketing site, portfolio, gallery
Optimizing Production Build
Use Next.js bundle analyzer
- Install the analyzer:
npm install @next/bundle-analyzer --save-devandnpm install cross-env --save-devin the project root - Update
package.jsonto have the following key-value pair in "scripts" - Configure
next.config.jsand set it as - Run the analyzer:
npm run analyzefor windows,ANALYZE=true npm run buildfor Mac/Linuxnpx cross-env ANALYZE=true npm run buildin the project root
"scripts": {
...
"analyze": "cross-env ANALYZE=true next build",
}import bundleAnalyzer from '@next/bundle-analyzer';
const withBundleAnalyzer = bundleAnalyzer({
enabled: process.env.ANALYZE === 'true',
});
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// swcMinify: true, // Next.js 14+ always minifies JS in production
compiler: {
// Remove console logs only in production
removeConsole: process.env.NODE_ENV === "production"
};
export default withBundleAnalyzer(nextConfig);Tips
- Tree-shake libraries : use named imports to only import components you use
import oneFunction from 'lodash/manyFunctions';- Dynamic imports : use dynamic imports for pages/components that are rarely used
- Instead of
import MasonryComponent from './MasonryComponentas normal, use dynamic import like below
import dynamic from 'next/dynamic';
// Dynamically import the MasonryComponent if it's a heavy component
const MasonryGallery = dynamic(
() => import('@/app/Responsive/masonry-gallery/page'),
{
loading: () => <p>Loading gallery...</p>, // Fallback UI while loading
ssr: false, // Optional: disables server-side rendering for this component
}
);
export default function MasonryPage() {
return (
<div>
<h1>Masonry Gallery</h1>
<MasonryGallery />
</div>
);
}Production Build
- Make sure to add the homepage URL to
package.jsonlike so"homepage": "https://<your-username>.github.io/<repo-name>/" - The only folder that is upload to the CDN is
_next/static/folder as everything else should not be exposed to the public
Deploying Static Next.js app to Github Pages
- Github Pages only supports static exports of React App, some extra requirements are needed to run Next.js app on Github
- Update
next.config.mjsfile so thatnextConfigobject so it has the following: - Add a file named
.nojekyllto thepublic/folder; this prevent Github from building a jekyll app
/* For Deploying to GitHub Pages as a static site (SSG) */
output: 'export', // generate a static site
distDir: 'out', // where to put the generated production build
images: {
unoptimized: true, // Next.js Images component will not load in Github pages if it uses Next.js image optimization
},- The static build for the Next.js site will be in the folder
out/inside the root folder; this is what Github Page uses - The static version will not have API routes, dynamic server rendering, middleware, and
getServerSideProps - The normal Next.js app build for the site will be in the folder
.next/inside the root folder