Skip to main content

Introduction

AnimeThemes Web is a Next.js application built with the Pages Router architecture. The project serves as a frontend for browsing anime opening and ending themes, providing static generation for optimal performance while supporting dynamic user interactions.

Technology Stack

Framework

  • Next.js 15 with Pages Router
  • React 19 for UI components
  • TypeScript for type safety

Styling

  • styled-components for component styling
  • Sass for global styles
  • Custom theme system with dark mode

Data Layer

  • GraphQL with schema merging
  • @tanstack/react-query for client state
  • SWR for authentication state

Build & Deploy

  • Static Site Generation (SSG)
  • Incremental Static Regeneration (ISR)
  • Server-Side Rendering (SSR) where needed

Architecture Diagram

Project Structure

The codebase follows a feature-based organization within a standard Next.js structure:
src/
├── pages/                 # Next.js Pages Router
│   ├── _app.tsx          # Application wrapper
│   ├── _document.tsx     # HTML document structure
│   ├── index.tsx         # Homepage
│   ├── anime/            # Anime pages
│   │   ├── [animeSlug]/
│   │   │   ├── index.tsx
│   │   │   └── [videoSlug]/
│   │   └── index.tsx
│   ├── artist/           # Artist pages
│   ├── search/           # Search pages
│   └── api/              # API routes
├── components/           # React components
│   ├── card/
│   ├── dialog/
│   ├── navigation/
│   └── video-player/
├── lib/                  # Core logic
│   ├── client/           # Client-side utilities
│   ├── common/           # Shared code
│   └── server/           # Server-side logic
├── hooks/                # Custom React hooks
├── context/              # React Context providers
├── generated/            # GraphQL generated types
├── styles/               # Global styles
├── theme/                # Theme configuration
└── utils/                # Helper functions

Key Architectural Patterns

1. Static Site Generation (SSG)

The application heavily leverages SSG for performance:
export const getStaticProps: GetStaticProps<AnimeDetailPageProps> = async ({ params }) => {
    const { data, apiRequests } = await fetchData<AnimeDetailPageQuery>(
        gql`
            query AnimeDetailPage($animeSlug: String!) {
                anime(slug: $animeSlug) {
                    ...AnimeDetailPageAnime
                }
            }
        `,
        params,
    );

    return {
        props: {
            ...getSharedPageProps(apiRequests),
            anime: data.anime,
        },
        // Revalidate after 1 hour
        revalidate: 3600,
    };
};

2. GraphQL Schema Merging

Multiple GraphQL APIs are merged into a unified schema:
import { mergeResolvers, mergeTypeDefs } from "@graphql-tools/merge";
import { makeExecutableSchema } from "@graphql-tools/schema";

export const schema = makeExecutableSchema({
    typeDefs: mergeTypeDefs([typeDefsAnimeThemes, typeDefsAnimeBracket]),
    resolvers: mergeResolvers([resolversAnimeThemes, resolversAnimeBracket]),
});

export const fetchData = buildFetchData(schema);

3. Context-Based State Management

The app uses React Context for global state:
interface PlayerContextInterface {
    watchList: WatchListItem[];
    setWatchList: (watchList: WatchListItem[]) => void;
    currentWatchListItem: WatchListItem | null;
    isGlobalAutoPlay: boolean;
    setGlobalAutoPlay: (autoPlay: boolean) => void;
    isRepeat: boolean;
    setRepeat: (repeat: boolean) => void;
}

Rendering Strategies

The application uses different rendering strategies based on page requirements:
Page TypeStrategyReason
Anime DetailSSG + ISRContent changes infrequently, revalidate hourly
Artist DetailSSG + ISRStatic content with periodic updates
SearchCSRHighly dynamic, user-specific queries
HomepageSSGFeatured content, regenerated on build
User ProfileSSRUser-specific, requires authentication

Data Flow

Performance Optimizations

Build-Time Caching

Pages cache API responses during build to avoid redundant requests:
const buildTimeCache: Map<string, AnimeDetailPageQuery> = new Map();

Concurrent Limiting

API requests are limited to prevent timeouts:
const limit = pLimit(5);

Smart Includes

GraphQL automatically determines required API includes based on query fields

ISR Revalidation

Pages revalidate after 1 hour (3600 seconds) to balance freshness and performance

Configuration

Key configuration in next.config.ts:
const nextConfig: NextConfig = {
    reactStrictMode: true,
    compiler: {
        styledComponents: true,
    },
    staticPageGenerationTimeout: 3600,
    experimental: {
        // Single-threaded for caching between page builds
        workerThreads: false,
        cpus: 1,
    },
};

Next Steps

Pages & Routing

Learn about the Pages Router structure and dynamic routes

GraphQL Layer

Understand the GraphQL implementation and schema merging

State Management

Explore React Query, SWR, and context-based state

Build docs developers (and LLMs) love