Next.js Discord

Discord Forum

Dynamic paths with output: export

Answered
Yacare Caiman posted this in #help-forum
Open in Discord
Yacare CaimanOP
I'm building a music player with Next.js + Tauri and want to add playlists to the app, they should be routable with slugs, i.e. /playlist/[id] but since Tauri requires to have the whole application be static (output: export), I get errors when trying to make a dynamic path.

Have anyone of you figured this out already? If I can't make this work, are there any suggestions / alternatives you reckon I should try? Thanks for the help in advance 😊

This is the error message I get, I'm using Next.js 14.2.1
Error: Page "/playlist/[id]/page" is missing exported function "generateStaticParams()", which is required with "output: export" config.
Answered by ᴉuɐpɹɐɐ
you can write all of your app's logic inside the /layout.tsx file therefore when the route change it doesnt trigger a server rerender (since there are no server...)
View full answer

16 Replies

Yacare CaimanOP
This is what I've written so far

// app/playlist/[id]/page.tsx
'use client';

import { Track } from '@/components/molecules';
import { TrackSkeleton } from '@/components/molecules/Track/components/skeleton';
import { usePlaySongHandler, useQueueStore, useSoundStore } from '@/hooks';
import { useQuery } from '@tanstack/react-query';
import axios from 'axios';
import { useState } from 'react';

export default function PlaylistPage({ params }: { params: { id: string } }) {
  const { id } = params;
  const [loading, setLoading] = useState(true);
  const song = useQueueStore((state) => state.song);
  const isPlaying = useSoundStore((state) => state.isPlaying);

  const fetchPlaylist = async (): Promise<any[]> => {
    console.log(params);
    const { data } = await axios.get(
      `https://server/playlist/${id}`,
    );
    data.forEach((track: any) => {
      track.src = track.source;
      track.authors = [track.authors[0].name];
      delete track.source;
    });
    setLoading(false);
    return data;
  };

  const { data } = useQuery({
    queryKey: ['singles'],
    queryFn: fetchPlaylist,
  });

  return (
    <div className="flex size-full flex-col items-center justify-between gap-12 overflow-auto p-6 pb-48 md:p-24">
      <div>
        {loading &&
          [...Array(12)].map((_, index) => (
            <TrackSkeleton key={index} className="w-full" />
          ))}

        {data?.map((track, index) => (
          <Track
            key={index}
            index={index + 1}
            {...track}
            selected={track.src === song?.src}
            playing={track.src === song?.src && isPlaying}
            className="w-full"
          />
        ))}
      </div>
    </div>
  );
}
@ᴉuɐpɹɐɐ try using generateStaticParams?
Yacare CaimanOP
I tried and I get this error
Error: Jest worker encountered 2 child process exceptions, exceeding retry limit.
But I'm not sure if this is a desirable approach though, my understanding is that this will fetch all the playlists and generate all the static paths with their IDs, but anyone can create and delete playlists, and there will be a ton of them.

import axios from 'axios';
import { PlaylistContent } from './components/Playlists';

export async function generateStaticParams() {
  const { data } = await axios.get('https://soundwaves.vercel.app/playlists');
  // Make sure shops is an array of shops at this point
  data.forEach((track: any) => {
    track.src = track.source;
    track.authors = [track.authors[0].name];
    delete track.source;
  });

  return data.map((single: any) => ({
    id: single.id.toString(),
  }));
}

export default async function PlaylistPage({
  params,
}: {
  params: { id: string };
}) {
  const { id } = params;
  const { data } = await axios.get(`https://soundwaves.vercel.app/playlists/${id}`);
  if (!data) return null;
  return <PlaylistContent data={data} />;
}
Yacare CaimanOP
thanks! I'll try right now
@ᴉuɐpɹɐɐ try `export const dynamic = "force-static"` instead of generate static params (remove the gsp)
Yacare CaimanOP
I wrote this and I'm getting this error still, maybe it's due to the output: export that's preventing force-dynamic? I also tried with force-static and get the exact same error.

Error: Page "/playlist/[id]/page" is missing exported function "generateStaticParams()", which is required with "output: export" config.

'use client';

import axios from 'axios';
import { PlaylistContent } from './components/Playlists';
import { useParams } from 'next/navigation';
import { useEffect, useState } from 'react';

export const dynamic = 'force-dynamic';

export default function PlaylistPage() {
  const { id } = useParams();
  const [data, setData] = useState<any[]>([]);

  useEffect(() => {
    const fetchPlaylist = async () => {
      console.log('id', id);
      const { data } = await axios.get(
        `https://soundwaves-server.vercel.app/playlist/${id}`,
      );
      setData(data);
    };

    fetchPlaylist();
  });

  if (!data) return null;
  return <PlaylistContent data={data} />;
}
Yacare CaimanOP
Yeah I tried building the app and this is the error I'm getting

Error: Page with dynamic = "force-dynamic" couldn't be exported. output: "export" requires all pages be renderable statically because there is not runtime server to dynamic render routes in this output format.
I wonder how Spotify and other apps do it, it's driving me nuts not being able to have dynamic paths
i.e in this case, tauri
you can just change the URL in the client side, and not put anything inside /[artistid]/page.jsx
you can write all of your app's logic inside the /layout.tsx file therefore when the route change it doesnt trigger a server rerender (since there are no server...)
Answer
Yacare CaimanOP
Yeah that works for me, thanks for the help!
Alligator mississippiensis