Office Address

43, Panerion ki Madri, Udaipur,
Rajasthan, India

Phone Number

+91 70140-40648

Email Address

contact@zenlogiclabs.com

hello@zenlogiclabs.com

Architecting a High-Performance Front-End App with Next.js: A Technical Leader’s Guide

Welcome to ZenLogic Labs! Today, we’re diving into the art of architecting a high-performance front-end application using Next.js. This guide will explore essential features like static site generation (SSG), caching, lazy loading, and more, making it a perfect resource for technical leaders and experienced developers looking to optimize their front-end frameworks.

In this blog, we’ll go through a real-world scenario where we’ll build an analytics dashboard for a large e-commerce platform. We’ll highlight how Next.js and a few powerful libraries can create an app that’s fast, SEO-friendly, and capable of handling heavy data loads. Ready to dig in? Let’s go!

Scenario Overview

The project we’re working on is a data-intensive analytics dashboard. This dashboard will serve a high-traffic e-commerce site with robust performance and SEO requirements. Users need quick access to various data-intensive dashboards, so we’ll leverage Next.js to handle tasks like SSG, caching, and lazy-loading seamlessly.

Key Tools and Libraries

Here’s the tech stack we’ll use to build our application:

  • Next.js: For its server-side rendering (SSR) and SSG capabilities.
  • React: Our go-to UI library.
  • Apollo Client: For managing data from our GraphQL API.
  • Chakra UI: A flexible, modular component library for styling.
  • SWR: For data fetching and caching.
  • TypeScript: To improve type safety and the developer experience.

Structuring the App

A clear file structure is key to maintainability. Here’s a clean setup to organize components, hooks, pages, services, and styles.

my-nextjs-app/
├── components/
│ ├── Header.tsx
│ ├── Footer.tsx
│ └── Dashboard/
│ ├── DashboardHeader.tsx
│ └── DashboardContent.tsx
├── hooks/
│ └── useDashboardData.ts
├── pages/
│ ├── index.tsx
│ ├── about.tsx
│ └── dashboards/
│ └── [id].tsx
├── services/
│ └── graphql.ts
├── styles/
│ └── globals.css
├── tests/
│ ├── components/
│ │ ├── Header.test.tsx
│ │ ├── Footer.test.tsx
│ │ └── Dashboard/
│ │ ├── DashboardHeader.test.tsx
│ │ └── DashboardContent.test.tsx
│ └── hooks/
│ └── useDashboardData.test.ts

4. Setting Up Next.js

To get started, create a new Next.js project and initialize TypeScript:

npx create-next-app my-nextjs-app –typescript
cd my-nextjs-app

Adding Chakra UI for Styling

Chakra UI is a versatile component library that simplifies styling. Install it with:

npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion

Wrap the app with ChakraProvider in _app.tsx to apply the theme globally: typescript Copy code

// pages/_app.tsx
import { AppProps } from 'next/app';
import { ChakraProvider } from '@chakra-ui/react';
import '../styles/globals.css';

function MyApp({ Component, pageProps }: AppProps) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
);
}

export default MyApp;

Connecting to GraphQL with Apollo Client

To connect to our GraphQL backend, install Apollo Client:

npm install @apollo/client graphql

Create a graphql.ts file to configure Apollo:

// services/graphql.ts
import { ApolloClient, InMemoryCache } from '@apollo/client';

const client = new ApolloClient({
uri: 'https://your-graphql-endpoint.com/graphql',
cache: new InMemoryCache(),
});

export default client;

Data Fetching with SWR

SWR makes data fetching and caching easy. Install it with:

npm install swr

Create a simple fetch utility:

// utils/fetcher.ts
export const fetcher = (url: string) => fetch(url).then((res) => res.json());

Implementing Static Site Generation

SSG helps Next.js pre-render pages for performance and SEO. Here’s how we can create a dynamic dashboard page:

// pages/dashboards/[id].tsx

import { GetStaticPaths, GetStaticProps } from 'next';
import { gql } from '@apollo/client';
import client from '../../services/graphql';
import useSWR from 'swr';
import { fetcher } from '../../utils/fetcher';
import { Box, Spinner } from '@chakra-ui/react';

const Dashboard = ({ initialData }) => {
const { data } = useSWR(`/api/dashboards/${id}`, fetcher, { initialData });

if (!data) return <Spinner />;

return (
<Box>
<h1>{data.dashboard.title}</h1>
</Box>
);
};

export const getStaticPaths: GetStaticPaths = async () => {
const { data } = await client.query({
query: gql`query { dashboards { id } }`,
});

const paths = data.dashboards.map(dashboard => ({
params: { id: dashboard.id.toString() },
}));

return { paths, fallback: true };
};

export const getStaticProps: GetStaticProps = async ({ params }) => {
const { data } = await client.query({
query: gql`query($id: ID!) { dashboard(id: $id) { id title } }`,
variables: { id: params.id },
});

return {
props: {
initialData: data,
},
revalidate: 10,
};
};

export default Dashboard;

9. Creating a Custom Hook for Reusability

By moving the dashboard data-fetching logic into a custom hook, we achieve reusability and cleaner components.

// hooks/useDashboardData.ts

import { useRouter } from 'next/router';
import useSWR from 'swr';
import { fetcher } from '../utils/fetcher';

export const useDashboardData = (initialData) => {
const router = useRouter();
const { data, error } = useSWR(`/api/dashboards/${id}`, fetcher, { initialData });

return {
data,
error,
isLoading: !error && !data,
};
};

Setting Up Unit Testing

Testing enhances code reliability and enables confident refactoring. Here’s how to set up Jest for unit testing:

Install Jest and supporting libraries:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom babel-jest @babel/preset-env @babel/preset-react @babel/preset-typescript

Configure Babel and Jest:

// .babelrc
{
"presets": ["next/babel", "@babel/preset-typescript"]
}
// jest.config.js
const nextJest = require('next/jest');
const createJestConfig = nextJest({ dir: './' });
module.exports = createJestConfig({
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleNameMapper: { '^@/components/(.*)$': '<rootDir>/components/$1' },
testEnvironment: 'jest-environment-jsdom',
});

Writing a Test

Once configured, start writing tests for core components. For example, here’s a test for our Header component:

// tests/components/Header.test.tsx
import { render, screen } from '@testing-library/react';
import Header from '../../components/Header';

describe('Header', () => {
it('renders the header', () => {
render(<Header />);
const headerElement = screen.getByText(/Header/i);
expect(headerElement).toBeInTheDocument();
});
});

Run your tests with:

Run your tests with:

npm test

Wrapping Up

And that’s it! We’ve built a high-performance Next.js app ready to handle real-world data and performance demands. This architecture ensures scalability, reusability, and a smooth development experience. Here at ZenLogic Labs, we believe that a well-architected front-end is the foundation of a reliable user experience, especially for data-heavy applications.

Stay tuned for more insights into front-end development best practices, and feel free to reach out if you’d like to learn more about building powerful applications with Next.js.