reactjstypescriptnext.jsdynamic-import

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.


Solution

  • 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} />;
    }
    

    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} />;
    }