NextJs: Statischer Export mit dynamischen Routen
Ich bin etwas verwirrt von der Dokumentation und nicht sicher, ob es möglich ist, was ich versuche zu tun.
Tor:
- Exportieren Sie die NextJS-App statisch und hosten Sie sie auf netlify
- Ermöglichen Sie Benutzern, Beiträge zu erstellen und Links zu diesen funktionierenden Beiträgen zu haben
Beispielsweise:
- Der Benutzer erstellt einen neuen Beitrag mit der ID: 2
- Dieser Beitrag sollte unter öffentlich zugänglich sein
mysite.com/posts/2
Ich würde mir vorstellen, dass ich eine HTML- posts.htmlSkelettdatei mit dem Namen erstellen und netlify alle posts/<id>Anforderungen an diese posts.htmlDatei umleiten kann , die dann das Skelett anzeigt und die erforderlichen Daten über eine API im laufenden Betrieb lädt .
Ich denke, ohne diesen Netlify-Hack ist mein Ziel des statischen Exports + funktionierende Links zu dynamischen Routen mit next.js laut Dokumentation nicht möglich, da dies fallback: truenur bei Verwendung von SSR möglich ist.
Frage: Wie kann ich mein Traum-Setup von statischem nextjs Export + funktionierenden Links zu dynamischen Routen verwirklichen?
EDIT: Ich habe gerade von Redirects erfahren . Sie könnten die Lösung für mein Problem sein.
Antworten
getStaticProps und getStaticPaths ()
Es sieht so aus, als ob getStaticProps und getStaticPaths () der richtige Weg sind.
Ich habe so etwas in meiner [post].jsDatei:
const Post = ({ pageContent }) => {
// ...
}
export default Post;
export async function getStaticProps({ params: { post } }) {
const [pageContent] = await Promise.all([getBlogPostContent(post)]);
return { props: { pageContent } };
}
export async function getStaticPaths() {
const [posts] = await Promise.all([getAllBlogPostEntries()]);
const paths = posts.entries.map((c) => {
return { params: { post: c.route } }; // Route is something like "this-is-my-post"
});
return {
paths,
fallback: false,
};
}
In meinem Fall frage ich Contentful mit meinem getAllBlogPostEntriesfür die Blogeinträge ab. Das schafft die Dateien, so etwas wie this-is-my-post.html. getBlogPostContent(post)greift auf den Inhalt der jeweiligen Datei zu.
export async function getAllBlogPostEntries() {
const posts = await client.getEntries({
content_type: 'blogPost',
order: 'fields.date',
});
return posts;
}
export async function getBlogPostContent(route) {
const post = await client.getEntries({
content_type: 'blogPost',
'fields.route': route,
});
return post;
}
Wenn ich ein mache npm run export, erstellt es eine Datei für jeden Blog-Beitrag ...
info - Collecting page data ...[
{
params: { post: 'my-first-post' }
},
{
params: { post: 'another-post' }
},
In Ihrem Fall routewäre das nur 1, 2, 3 usw.
Veraltete Methode - Führen Sie eine Abfrage in next.config.js aus
Wenn Sie eine statische Site erstellen möchten, müssen Sie die Beiträge vor dem abfragen next export.
Hier ist ein Beispiel für die Verwendung von Contentful, das Sie möglicherweise mit Blog-Posts eingerichtet haben:
Erstellen Sie zunächst eine Seite unter pages/blog/[post].js.
Weiter kann ein exportMapInnenraum verwendet werden next.config.js.
// next.config.js
const contentful = require('contentful');
// Connects to Contentful
const contentfulClient = async () => {
const client = await contentful.createClient({
space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE_ID,
accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN,
});
return client;
};
// Gets all of the blog posts
const getBlogPostEntries = async (client) => {
const entries = await client.getEntries({
content_type: 'blogPost',
order: 'fields.date',
});
return entries;
};
module.exports = {
async exportPathMap() {
const routes = {
'/': { page: '/' }, // Index page
'/blog/index': { page: '/blog' }, // Blog page
};
const client = await contentfulClient();
const posts = await getBlogPostEntries(client);
// See explanation below
posts.items.forEach((item) => {
routes[`/blog/${item.fields.route}`] = { page: '/blog/[post]' };
});
return routes;
},
};
Direkt darüber verbinde return routes;ich mich mit Contentful und greife nach allen Blog-Posts. In diesem Fall hat jeder Beitrag einen von mir definierten Wert namens route. Ich habe jedem Inhalt einen Routenwert gegeben, so etwas wie this-is-my-first-postund just-started-blogging. Am Ende sieht das Routenobjekt ungefähr so aus:
routes = {
'/': { page: '/' }, // Index page
'/blog/index': { page: '/blog' }, // Blog page
'/blog/this-is-my-first-post': { page: '/blog/[post]' },
'/blog/just-started-blogging': { page: '/blog/[post]' },
};
Ihr Export in das out/Verzeichnis lautet:
out/
/index.html
/blog/index.html
/blog/this-is-my-first-post.html
/blog/just-started-blogging.html
In Ihrem Fall müssten Sie, wenn Sie Post-ID-Nummern verwenden, die Blog-Posts abrufen und Folgendes tun:
const posts = await getAllPosts();
posts.forEach((post) => {
routes[`/blog/${post.id}`] = { page: '/blog/[post]' };
});
// Routes end up like
// routes = {
// '/': { page: '/' }, // Index page
// '/blog/index': { page: '/blog' }, // Blog page
// '/blog/1': { page: '/blog/[post]' },
// '/blog/2': { page: '/blog/[post]' },
// };
Der nächste Schritt wäre, eine Art Hook für Netlify zu erstellen, um einen statischen Site-Build auszulösen, wenn der Benutzer Inhalte erstellt.
Auch hier ist eine Vorstellung davon, wie Sie pages/blog/[post].jsaussehen würden.
import Head from 'next/head';
export async function getBlogPostContent(route) {
const post = await client.getEntries({
content_type: 'blogPost',
'fields.route': route,
});
return post;
}
const Post = (props) => {
const { title, content } = props;
return (
<>
<Head>
<title>{title}</title>
</Head>
{content}
</>
);
};
Post.getInitialProps = async ({ asPath }) => {
// asPath is something like `/blog/this-is-my-first-post`
const pageContent = await getBlogPostContent(asPath.replace('/blog/', ''));
const { items } = pageContent;
const { title, content } = items[0].fields;
return { title, content };
};
export default Post;