Next.js Discord

Discord Forum

Next Build config with "output: "export"" failing

Unanswered
Barbary Lion posted this in #help-forum
Open in Discord
Barbary LionOP
Hey all,

I am trying to export my application as an SPA. I updated my next.config to have output: "export, but when I build my application it fails due to: is missing "generateStaticParams()" so it cannot be used with "output: export" config. for my dynamic routes. If I do not have output: "export" in my next.config my build works as expected, but is not being built as a static application. I am trying to build it as a static application because I use the static assets as the frontend for my wails desktop application.

My dynamic routes are structed in a sever a client component. My server component is the page.tsx and my client component is pageClient.tsx. My page.tsx exports dynamicParams = false and exports an empty static parameter generator and my client component uses 'use client':

page.tsx
import Page from './pageClient';

export const dynamicParams = false;

export async function generateStaticParams() {
  return [ { slug: [""] } ];
}

const EditBudgetPage = (props: any) => {
  return <Page {...props} />
};

export default EditBudgetPage;


pageClient.tsx
'use client';

import { useRouter } from 'next/navigation';

import { UpdateBudgetRequest } from '@tooler-web/_api/financeClient';
import {
  useGetBudgetQuery,
  useGetCategoriesQuery,
  useUpdateBudgetMutation,
} from '@tooler-web/_redux/finance/finance.api';

import { Card, CardHeader, Title1 } from '@fluentui/react-components';
import FullPage from '@tooler-web/_components/FullPage';
import { BudgetEditForm } from '@tooler-web/_components/Form/BudgetForm';

type IdRouteSegmentParams = {
  params: {
    id: string;
  };
};

type EditBudgetPageProps = {} & IdRouteSegmentParams;

const EditBudgetPage = (props: EditBudgetPageProps) => {
  const router = useRouter();
  const {
    data: categories,
    isLoading: isLoadingCategories,
    error: errorLoadingCategories,
  } = useGetCategoriesQuery({ userId: '1' });
  const {
    data: budget,
    isLoading: isLoadingBudget,
    error: getBudgetError,
  } = useGetBudgetQuery(props.params.id);
  const [
    updateBudget,
    { isLoading: isUpdatingBudget, error: updatingBudgetError },
  ] = useUpdateBudgetMutation();

  const handleUpdateBudgetClick = async (request: UpdateBudgetRequest) => {
    try {
      await updateBudget(request);

      router.push('/finance');
    } catch {}
  };

  return (
    <FullPage>
      <Card>
        <CardHeader header={<Title1>Edit budget</Title1>} />
        <BudgetEditForm
          budget={budget?.budget}
          onUpdateBudgetClick={handleUpdateBudgetClick}
          isSubmitting={isUpdatingBudget}
          isLoadingBudget={isLoadingBudget}
          errorLoadingBudget={getBudgetError || updatingBudgetError}
          errorSubmitting={updatingBudgetError}
          categories={categories?.categories}
          isLoadingCategories={isLoadingCategories}
          errorLoadingCategories={errorLoadingCategories}
        />
      </Card>
    </FullPage>
  );
};

export default EditBudgetPage;


I am a bit confused my next.js build is failing when trying to build a static application with the error message: is missing "generateStaticParams()" so it cannot be used with "output: export" config. for my dynamic components when I set dynamicParams to false and generate static params. Does anyone have tips on what I am doing wrong or other things I need to change to be able to build a static application with the output: "export" next.config?

8 Replies

Barbary LionOP
Any ideas?
do you have any other dynamic pages?
Barbary LionOP
I just have a route group page and dynamic pages that I take the id out of the route. For example, the route “category/edit/1” I would take one and make an api request looking up that category.
Would a screen shot of my App layout help?
Barbary LionOP
The budget, acccount, and transaction routes all follow the same pattern as the expanded account routes.

Also, all my dynamic pages contain dynamicParams = false and generateStaticParams function:
export const dynamicParams = false;

export async function generateStaticParams() {
  return [ { slug: [""] } ];
}


I'm not sure what I am missing or why I would recieve a message on a page that is missing "generateStaticParams()" so it cannot be used with "output: export" config. when the generateStaticParams is their.
@joulev before the "is missing "generateStaticParams()"" phrase there should be the slug to the page. what is that slug?
Barbary LionOP
I just broke down my application to just the transactions pages now to figure out what is going on. I don't understand why I need to have a getstaticparams function when I do not want to pre render the page since the client will get the id from the path and make an api call for the data.
@joulev before the "is missing "generateStaticParams()"" phrase there should be the slug to the page. what is that slug?
Barbary LionOP
Here is that exact error when I set id to any empty string: Error: Page "/finance/transaction/edit/[id]" is missing "generateStaticParams()" so it cannot be used with "output: export" config.. I'm confused why I even need the generateStaticParams if I am building a static SPA. The client will get the id from the route and then use that id to make an api request to get data to display on the page.

page.tsx:
import Page from './pageClient';

export const dynamicParams = false;

export async function generateStaticParams() {
  return [];
}

const EditTransactionPage = (props: any) => {
  return <Page {...props} />;
};

export default EditTransactionPage;


pageClient.tsx:
'use client';

import React from 'react';
import { useRouter } from 'next/navigation';

import { UpdateTransactionRequest } from '@tooler-web/_api/financeClient';
import {
  useGetCategoriesQuery,
  useGetTransactionQuery,
  useGetAccountsQuery,
  useUpdateTransactionMutation,
} from '@tooler-web/_redux/finance/finance.api';

import { Card, CardHeader, Title1 } from '@fluentui/react-components';
import FullPage from '@tooler-web/_components/FullPage';
import { TransactionEditForm } from '@tooler-web/_components/Form/TransactionForm';

type IdRouteSegmentParams = {
  params: {
    id: string;
  };
};

type EditTransactionPageProps = {} & IdRouteSegmentParams;

const EditTransactionPage: React.FC<EditTransactionPageProps> = (props) => {
  const router = useRouter();
  const {
    data: accounts,
    isLoading: isLoadingAccounts,
    error: errorLoadingAccounts,
  } = useGetAccountsQuery({});
  const {
    data: categories,
    isLoading: isLoadingCategories,
    error: errorLoadingCategories,
  } = useGetCategoriesQuery({ userId: '1' });
  const {
    data: transaction,
    isLoading: isLoadingTransaction,
    error: getTransactionError,
  } = useGetTransactionQuery(props.params.id);
  const [
    updateTransaction,
    { isLoading: isUpdatingTransaction, error: updatingTransactionError },
  ] = useUpdateTransactionMutation();

  const handleUpdateTransactionClick = async (
    request: UpdateTransactionRequest
  ) => {
    try {
      await updateTransaction(request);

      router.push('/finance');
    } catch {}
  };

  return (
    <FullPage>
      <Card>
        <CardHeader header={<Title1>Edit transaction</Title1>} />
        <TransactionEditForm
          accounts={accounts?.accounts}
          isLoadingAccounts={isLoadingAccounts}
          errorLoadingAccounts={errorLoadingAccounts}
          categories={categories?.categories}
          isLoadingCategories={isLoadingCategories}
          errorLoadingCategories={errorLoadingCategories}
          transaction={transaction?.transaction}
          onUpdateTransactionClick={handleUpdateTransactionClick}
          isSubmitting={isUpdatingTransaction}
          isLoading={isLoadingTransaction}
          error={getTransactionError || updatingTransactionError}
        />
      </Card>
    </FullPage>
  );
};

export default EditTransactionPage;