Dixit Ram
Dixit Ram

Reputation: 83

Next.js: How to optimize dynamic template loading to prevent unnecessary template files from being fetched

Problem

I have a Next.js application where I'm dynamically loading portfolio templates based on user preferences. While the functionality works, I noticed in the developer console that all template files are being fetched, even though only one template is needed at a time.

Current Implementation

I have a dynamic route [username] that loads user data and their chosen template:

// app/[username]/page.tsx
import { notFound } from "next/navigation";
import data from "@/public/FakeData.json"

const users = data.users;

export default async function userPortfolio({ params }: { params: { username: string } }) {
    const user = users.filter((u)=>{
        return u.username == params.username; 
    }).at(0);
    
    if (!user) {
        return notFound();
    }

    let userTemplate = user.template;

    // This loads all template files even though we only need one
    const TemplatePage = (await import(`@/components/Templates/${userTemplate}/${userTemplate}_Portfolio`)).default;
 
    return (
        <TemplatePage userDetails={user} />
    );
}

My template files are structured like this:

components/
  Templates/
    Marc/
      Marc_Portfolio.jsx
    Rahul/
      Rahul_Portfolio.tsx

Expected Behavior

When a user visits /james123 and their template is "Marc", only the Marc template files should be fetched, not the Rahul template files.

Current Behavior

When checking the Network tab in Chrome DevTools, I can see that files from all templates are being fetched, even though only one template is being used.

Question

How can I optimize the dynamic imports to only fetch the specific template files that are needed, without loading other template files?

Additional Context

What I've Tried

I've attempted using dynamic imports with template strings, but this seems to cause Next.js to include all possible template files in the bundle.

Upvotes: 0

Views: 35

Answers (1)

Dixit Ram
Dixit Ram

Reputation: 83

Here’s a refined version of your solution with improved grammar, explanation, and structure for better clarity:


Solution

To solve this issue, I used next/dynamic to dynamically import the required template. However, I initially encountered an error:

'ssr: false' is not allowed with `next/dynamic` in Server Components. Please move it into a client component.

Since ssr: false requires a Client Component, I created a separate client-side component to handle the dynamic import.


Step 1: Define Schema for Props

I created a schema file (types.ts) to define the types for user data and component props:

export interface UserSchema {
  username: string;
  template: string;
  name: string;
  profile_picture: string;
  location: string;
  cvURL: string;
  contact: {
    email: string;
    linkedin: string;
    github: string;
  };
  profile_summary: string;
  experience: any[];
}

export interface TemplatePageProps {
  userDetails: UserSchema;
}

export interface ClientTemplateProps {
  user: UserSchema;
  templateName: string;
}

Step 2: Create a Client Component for Dynamic Import

I created a separate client component (ClientTemplate.tsx) to dynamically load the required template based on the user's templateName.

'use client';

import dynamic from 'next/dynamic';
import { ClientTemplateProps, TemplatePageProps } from './types';

export default function ClientTemplate({ user, templateName }: ClientTemplateProps) {
  const TemplatePage = dynamic<TemplatePageProps>(
    () => import(`@/components/Templates/${templateName}/${templateName}_Portfolio`),
    { ssr: false }
  );

  return <TemplatePage userDetails={user} />;
}
  • This ensures that the template is only loaded on the client side, preventing unnecessary server-side rendering issues.
  • The ssr: false option ensures that the template is loaded dynamically in the browser rather than preloaded on the server.

Step 3: Modify page.tsx to Use the Client Component

Finally, I updated page.tsx to use ClientTemplate for rendering the correct template dynamically:

import { notFound } from "next/navigation";
import ClientTemplate from "./ClientTemplate";
import data from "@/public/FakeData.json";

const users = data.users;

export default async function userPortfolio({ params }: { params: { username: string } }) {
    const user = users.find((u) => u.username === params.username);
    
    if (!user) return notFound();

    return <ClientTemplate user={user} templateName={user.template} />;
}

Upvotes: 0

Related Questions