Is there a way to create a dynamic payload for static site?

I am creating a blog page and i need to fetch the content dynamically. Is there a way to do it with nuxt generate because my hosting provider doesn't support server. It's using cpanel and I cant make it work dynamically.
13 Replies
kapa.ai
kapa.ai3w ago
Hi @Kaloyanes. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, there is a way to create a dynamic payload for a static site in Nuxt, which can be particularly useful for blog pages. This can be achieved using Nuxt's static site generation capabilities combined with payload extraction. Here's how you can approach this: 1. Use nuxt generate command: The nuxt generate command will pre-render your pages and create a static version of your site. This is suitable for hosting providers that don't support server-side rendering. 2. Enable payload extraction: To enable dynamic content fetching in a static site, you can use the payload extraction feature. Add the following to your nuxt.config.ts:
export default defineNuxtConfig({
experimental: {
payloadExtraction: true
}
})

export default defineNuxtConfig({
experimental: {
payloadExtraction: true
}
})

Experimental Features explains that this enables extraction of payloads for pages generated with nuxt generate. 3. Use useFetch or useAsyncData in your components: These composables will ensure that your data is fetched during the build process and included in the generated payload. 4. Implement your blog page: Create a blog page that fetches content dynamically. Here's an example:
<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>

<template>
<div>
<h1>Blog Posts</h1>
<ul>
<li v-for="post in posts" :key="post.id">
{{ post.title }}
</li>
</ul>
</div>
</template>

<script setup lang="ts">
const { data: posts } = await useFetch('/api/posts')
</script>

<template>
<div>
<h1>Blog Posts</h1>
<ul>
<li v-for="post in posts" :key="post.id">
{{ post.title }}
</li>
</ul>
</div>
</template>

5. Generate your static site: Run npx nuxi generate to build your static site. This will create a .output/public directory with your static files. By following these steps, you can create a static site with dynamic content that works on hosting providers without server-side support, like cPanel. The payload extraction feature allows you to fetch content dynamically even in a static environment. For more detailed information on static site generation and prerendering, you can refer to the Nuxt Prerendering documentation. Remember that this approach pre-renders your content at build time. If you need to update your blog content, you'll need to rebuild and redeploy your site. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@258614283909201920> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Omnislash
Omnislash3w ago
I understand it's not the answer your are expecting, but you might want to consider cloudflare pages instead ? It's free up to pretty far and you'll most likely have less deployment restrictions ? that being said, why is the kappa answer not ok for you ? It does fetch the content with a static website without using nitro isn't it ?
Kaloyanes
KaloyanesOP3w ago
It's by my employer that i use their hosting provider : ( And when i nuxi generate it doesnt create api routes because it's static. In my api i am just redirecting to a utils function because of the env variables. I can't access them on the client side
Omnislash
Omnislash3w ago
My bad ofc it doesn't work, I use nuxt just as a front, so fetch works but it indeed fetches data from elsewhere ^^""" I would argue you indeed can't have the server side in any static hosting. So if cpanel only does static hosting..... That being said, you have a public and a private env. You can access the public env on the client side. It's here in runtime config : https://nuxt.com/docs/guide/going-further/runtime-config You just have to prefix the variable with NUXT_PUBLIC_
Kaloyanes
KaloyanesOP3w ago
doesnt give me to access them using the runtime config on utils function dunno will try to use the runtime config from the blog page and just redirect it to the utils function with a variable
Omnislash
Omnislash3w ago
Are you sure you call it from a nuxt context ? You have an error pour an empty runtime config ?
Kaloyanes
KaloyanesOP3w ago
well from the utils i think its not nuxt context
Omnislash
Omnislash3w ago
The utils itself is not indeed if i remember correctly, but it doesn't mean you can't call it from a nuxt context, like a component script setup for exemple
Kaloyanes
KaloyanesOP3w ago
Well when I do call it from there it gives me the error that there isn't a nuxt context
Omnislash
Omnislash3w ago
Can you share the utils code that gets the runtime config ?
Kaloyanes
KaloyanesOP3w ago
alright now the new problem is that the cors doesn't work
import type {
BlockObjectResponse,
PageObjectResponse,
QueryDatabaseParameters,
} from "@notionhq/client/build/src/api-endpoints";
import { Client } from "@notionhq/client";

export const getClient = () => {
const config = useRuntimeConfig();
const token = config.public.token;

if (!token)
throw new Error(
"The NUXT_PUBLIC_NOTION_TOKEN environment variable is required",
);

return new Client({
auth: token,
fetch: async (url, options) => {
const corsOptions = {
...options,
headers: {
...options?.headers,
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
};

const response = await fetch(url, corsOptions);

if (response.status === 429) {
const retryAfter = response.headers.get("Retry-After");
if (retryAfter) {
const retryAfterSeconds = Number.parseInt(retryAfter, 10);
await new Promise((resolve) =>
setTimeout(resolve, retryAfterSeconds),
);
return fetch(url, corsOptions);
}
}

return response;
},
});
};

export const fetchPages = async (language: string, status = "Live") => {
const config = useRuntimeConfig();

const notionClient = getClient();

const databaseId = config.public.databaseId;
if (!databaseId) {
throw new Error(
"The NUXT_PUBLIC_NOTION_DATABASE_ID environment variable is required.",
);
}

const args: QueryDatabaseParameters = {
database_id: databaseId,
};

console.log("Fetching pages with status", status);
if (status !== "All")
args.filter = {
property: "status",
status: {
equals: status,
},
and: [{ property: "language", select: { equals: language } }],
};

return await notionClient.databases.query(args);
};
import type {
BlockObjectResponse,
PageObjectResponse,
QueryDatabaseParameters,
} from "@notionhq/client/build/src/api-endpoints";
import { Client } from "@notionhq/client";

export const getClient = () => {
const config = useRuntimeConfig();
const token = config.public.token;

if (!token)
throw new Error(
"The NUXT_PUBLIC_NOTION_TOKEN environment variable is required",
);

return new Client({
auth: token,
fetch: async (url, options) => {
const corsOptions = {
...options,
headers: {
...options?.headers,
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
};

const response = await fetch(url, corsOptions);

if (response.status === 429) {
const retryAfter = response.headers.get("Retry-After");
if (retryAfter) {
const retryAfterSeconds = Number.parseInt(retryAfter, 10);
await new Promise((resolve) =>
setTimeout(resolve, retryAfterSeconds),
);
return fetch(url, corsOptions);
}
}

return response;
},
});
};

export const fetchPages = async (language: string, status = "Live") => {
const config = useRuntimeConfig();

const notionClient = getClient();

const databaseId = config.public.databaseId;
if (!databaseId) {
throw new Error(
"The NUXT_PUBLIC_NOTION_DATABASE_ID environment variable is required.",
);
}

const args: QueryDatabaseParameters = {
database_id: databaseId,
};

console.log("Fetching pages with status", status);
if (status !== "All")
args.filter = {
property: "status",
status: {
equals: status,
},
and: [{ property: "language", select: { equals: language } }],
};

return await notionClient.databases.query(args);
};
my newly added code is the headers to the fetch in the client I am trying to use Notion as a CMS which has worked in the server but not the static version damn so there isn't a solution except for choosing a different hosting provider
Omnislash
Omnislash3w ago
Oh ok just understood the question :x Indeed CROS is server-side @Kaloyanes I do use Notion as a CMS myself so it works, but I guess they prevent it from the browser since you should never use your access or API Keys from you front That being said, the notion api response time is underwhelming, especially since you usually need more than one call to have all the info you want to display on one page, so I ended up using postgres as a "cache"

Did you find this page helpful?