Qwik SSG not being able to generate static pages that requires API calls

63 Views Asked by At

I'm trying to learn the Qwik framework and I'm trying to understand how to dynamically build static pages that requires API calls to populate the content

I have a route that's festival/[slug]/index.tsx. Before I had the routeLoader$ functionality that fetched content from an API server-side.

Right now I'm trying to convert this functionality into statically-generated pages.

I've followed the instruction of the docs (https://qwik.dev/docs/guides/static-site-generation/):

  1. I've ran the npm run qwik add static command
  2. To build the static pages I use npm run build.server
  3. I've added the onStaticGenerate method inside the index.tsx like this
export const onStaticGenerate: StaticGenerateHandler = async () => {
  const { allFestivals } = await performRequest<IGetAllFestivalSlugs>({
    query: GET_ALL_FESTIVAL_SLUGS,
  });

  return {
    params: allFestivals.map(({ slug }) => {
      return { slug };
    }),
  };
};

So now I get all slugs dynamically from the APIs correctly, and I can generate the page statically.

The problem is that I don't know how to fetch datas for all the pages dynamically.

I know I shouldn't use routeLoader$ since it's a server-side function.

Also I don't know how to populate the DocumentHead since before I used the resolveValue with the routeLoader$ in order to get the content.

Here's what my index.tsx looks like:

import { component$ } from "@builder.io/qwik";
import type {
  RequestEventLoader,
  StaticGenerateHandler,
} from "@builder.io/qwik-city";
import { routeLoader$ } from "@builder.io/qwik-city";

import { type DocumentHead } from "@builder.io/qwik-city";
import {
  GET_ALL_FESTIVAL_SLUGS,
  GET_SINGLE_FESTIVAL,
} from "~/lib/constants/api/queries";
import { performRequest } from "~/lib/datocms";
import type {
  IGetAllFestivalSlugs,
  IGetSingleFestival,
} from "~/lib/models/cms";

export const useGetFestivalDetail = routeLoader$(
  async (event: RequestEventLoader) => {
    const res = await performRequest<IGetSingleFestival>({
      query: GET_SINGLE_FESTIVAL,
      variables: { slug: event.params.slug },
    });
    return res.festival;
  },
);

export default component$(() => {
  const { value } = useGetFestivalDetail();

  return (
    <>
      <h2>{value.title}</h2>
      <p>{value.description}</p>
    </>
  );
});

export const onStaticGenerate: StaticGenerateHandler = async () => {
  const { allFestivals } = await performRequest<IGetAllFestivalSlugs>({
    query: GET_ALL_FESTIVAL_SLUGS,
  });

  return {
    params: allFestivals.map(({ slug }) => {
      return { slug };
    }),
  };
};

export const head: DocumentHead = ({ resolveValue }) => {
  const festival = resolveValue(useGetFestivalDetail);
  const meta = festival.seo
    .filter((tag) => tag.attributes !== null)
    .map(({ attributes }) => ({
      property: attributes?.property,
      content: attributes?.content,
    }));

  return { title: festival.title, meta };
};

I'm using DatoCMS as headless CMS through GraphQL.

One thing I've tried: I've tried to put all data inside the return inside onStaticGenerate but as far as I've understood I should just pass the path params, also I cannot put any values inside inside the head object.

adapters/static/vite-config.ts:

import { staticAdapter } from "@builder.io/qwik-city/adapters/static/vite";
import { extendConfig } from "@builder.io/qwik-city/vite";
import baseConfig from "../../vite.config";

export default extendConfig(baseConfig, () => {
  return {
    build: {
      ssr: true,
      rollupOptions: {
        input: ["@qwik-city-plan"],
      },
    },
    plugins: [
      staticAdapter({
        origin: "https://yoursite.qwik.dev",
      }),
    ],
  };
});

vite.config.ts inside my root project:

import { defineConfig } from "vite";
import { qwikVite } from "@builder.io/qwik/optimizer";
import { qwikCity } from "@builder.io/qwik-city/vite";
import tsconfigPaths from "vite-tsconfig-paths";

export default defineConfig(() => {
  return {
    plugins: [qwikCity(), qwikVite(), tsconfigPaths()],
    dev: {
      headers: {
        "Cache-Control": "public, max-age=0",
      },
    },
    preview: {
      headers: {
        "Cache-Control": "public, max-age=600",
      },
    },
  };
});

0

There are 0 best solutions below