Salta ai contenuti

Tutorial - Esteso con le Collezioni di Contenuti

Le collezioni di contenuto sono un modo potente per gestire gruppi di contenuti simili, come i post del blog. Le collezioni aiutano ad organizzare i tuoi documenti, a convalidare il tuo frontmatter YAML e a fornire automaticamente la sicurezza del tipo TypeScript per tutti i tuoi contenuti (anche se non scrivi alcun TypeScript tu stesso).

Preparati a…

  • Sposta la tua cartella di post del blog in src/content/
  • Crea uno schema per definire il tuo frontmatter dei post del blog
  • Usa getCollection() per ottenere contenuti e metadati dei post del blog

Avrai bisogno di un progetto Astro esistente con file Markdown o MDX nella cartella src/pages/.

Questo tutorial usa il progetto finito della guida Build a Blog per dimostrare come convertire un blog in collezioni di contenuti. Puoi fare il fork e usare quella base di codice in locale, o completare il tutorial nel browser modificando il codice della guida al blog in StackBlitz.

Puoi invece seguire questi passaggi con il tuo progetto Astro, ma dovrai adattare le istruzioni alla tua base di codice.

Ti consigliamo di utilizzare il nostro progetto di esempio per completare prima questo breve tutorial. Poi, puoi usare ciò che hai imparato per creare collezioni di contenuti nel tuo progetto.

Nella guida introduttiva Build a Blog, hai imparato il routing basato su file integrato di Astro: qualsiasi file .astro, .md o .mdx ovunque nella cartella src/pages/ diventava automaticamente una pagina del tuo sito.

Per creare il tuo primo post sul blog su https://example.com/posts/post-1/, hai creato una cartella /posts/ e aggiunto il file post-1.md. Poi hai aggiunto un nuovo file Markdown a questa cartella ogni volta che volevi aggiungere un nuovo post al tuo sito.

Anche quando stai usando le collezioni di contenuti, userai ancora la cartella src/pages/ per le pagine individuali, come la tua pagina About Me. Ma, spostando i tuoi post del blog nella cartella speciale src/content/ ti permetterà di usare API più potenti e performanti per generare l’indice dei post del blog e visualizzare i tuoi post del blog individuali.

Allo stesso tempo, riceverai una migliore guida e autocompletamento nel tuo editor di codice perché avrai uno schema per definire una struttura comune per ogni post che Astro ti aiuterà ad applicare. Nel tuo schema, puoi specificare quando le proprietà del frontmatter sono richieste, come una descrizione o un autore, e quale tipo di dati deve essere ogni proprietà, come una stringa o un array. Questo porta a cogliere molti errori prima, con messaggi di errore descrittivi che ti dicono esattamente qual è il problema.

Leggi di più sulle collezioni di contenuti di Astro nella nostra guida, o inizia con le istruzioni qui sotto per convertire un blog di base da src/pages/posts/ a src/content/posts/.

  1. Quale pagina dovresti tenere in src/pages/?

  2. Quale non è un vantaggio dello spostamento dei post del blog in una collezione di contenuti?

  3. Le collezioni di contenuto usano TypeScript per…

Estendere il blog di tutorial con le collezioni di contenuti

Sezione intitolata Estendere il blog di tutorial con le collezioni di contenuti

Gli step seguenti mostrano come estendere il prodotto finale della guida Build a Blog creando una collezione di contenuti per i post del blog.

  1. Aggiorna all’ultima versione di Astro, e aggiorna tutte le integrazioni alle loro ultime versioni eseguendo i seguenti comandi nel tuo terminale:

    Terminal window
    # Upgrade to Astro v4.x
    npm install astro@latest
    # Example: upgrade the blog tutorial Preact integration
    npm install @astrojs/preact@latest
  2. Il blog di tutorial usa l’impostazione TypeScript base (meno rigorosa). Per usare le collezioni di contenuto, devi configurare TypeScript per le collezioni di contenuto o usando l’impostazione strict o strictest, o aggiungendo due opzioni in tsconfig.json.

    Per usare le collezioni di contenuto senza scrivere TypeScript nel resto dell’esempio della guida al blog, aggiungi le seguenti due opzioni di configurazione TypeScript al file di configurazione:

    tsconfig.json
    {
    // Note: Non devi cambiare niente se usi "astro/tsconfigs/strict" o "astro/tsconfigs/strictest"
    "extends": "astro/tsconfigs/base",
    "compilerOptions": {
    "strictNullChecks": true,
    "allowJs": true
    }
    }

Crea una collezione per i post del tuo blog

Sezione intitolata Crea una collezione per i post del tuo blog
  1. Crea una nuova collezione (cartella) chiamata src/content/posts/.

  2. Sposta tutti i tuoi post del blog esistenti (file .md) da src/pages/posts/ in questa nuova collezione.

  3. Crea un file src/content/config.ts per definire uno schema per la tua postsCollection. Per il codice esistente della guida al blog, aggiungi il seguente contenuto al file per definire tutte le proprietà del frontmatter usate nei post del blog:

    src/content/config.ts
    // Import utilities from `astro:content`
    import { z, defineCollection } from "astro:content";
    // Definisci un `type` e uno `schema` per ogni collezione
    const postsCollection = defineCollection({
    type: 'content',
    schema: z.object({
    title: z.string(),
    pubDate: z.date(),
    description: z.string(),
    author: z.string(),
    image: z.object({
    url: z.string(),
    alt: z.string()
    }),
    tags: z.array(z.string())
    })
    });
    // Esporta un singolo oggetto `collections` per registrare la tua collezione
    export const collections = {
    posts: postsCollection,
    };
  4. Per consentire ad Astro di riconoscere il tuo schema, interrompi il server di sviluppo (CTRL + C) e esegui il seguente comando: npx astro sync. Questo definirà il modulo astro:content per l’API delle Collezioni di Contenuti. Riavvia il server di sviluppo per continuare con il tutorial.

  1. Crea un file per la pagina chiamato src/pages/posts/[...slug].astro. I tuoi file Markdown e MDX non diventano più automaticamente pagine usando il routing basato su file di Astro quando sono all’interno di una collezione, quindi devi creare una pagina responsabile per generare ogni singolo post del blog.

  2. Aggiungi il codice seguente per interrogare la tua collezione per rendere disponibile a ogni pagina che genererà lo slug e il contenuto della pagina di ogni post del blog:

    src/pages/posts/[...slug].astro
    ---
    import { getCollection } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';
    export async function getStaticPaths() {
    const blogEntries = await getCollection('posts');
    return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
    }));
    }
    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
  3. Renderizza il tuo <Content /> del post all’interno del layout per le pagine Markdown. Questo ti permette di specificare un layout comune per tutti i tuoi post.

    src/pages/posts/[...slug].astro
    ---
    import { getCollection } from 'astro:content';
    import MarkdownPostLayout from '../../layouts/MarkdownPostLayout.astro';
    export async function getStaticPaths() {
    const blogEntries = await getCollection('posts');
    return blogEntries.map(entry => ({
    params: { slug: entry.slug }, props: { entry },
    }));
    }
    const { entry } = Astro.props;
    const { Content } = await entry.render();
    ---
    <MarkdownPostLayout frontmatter={entry.data}>
    <Content />
    </MarkdownPostLayout>
  4. Rimuovi la definizione layout nel frontmatter di ogni singolo post. Il tuo contenuto è ora racchiuso in un layout quando viene renderizzato, e questa proprietà non è più necessaria.

    src/content/posts/post-1.md
    ---
    layout: ../../layouts/MarkdownPostLayout.astro
    title: 'My First Blog Post'
    pubDate: 2022-07-01
    ...
    ---

Rimpiazza Astro.glob() con getCollection()

Sezione intitolata Rimpiazza Astro.glob() con getCollection()
  1. Ovunque tu abbia una lista di post del blog, come la pagina Blog della guida (src/pages/blog.astro/), dovrai sostituire Astro.glob() con getCollection() come modo per recuperare contenuti e metadati dai tuoi file Markdown.

    src/pages/blog.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";
    const pageTitle = "My Astro Learning Blog";
    const allPosts = await Astro.glob("../pages/posts/*.md");
    const allPosts = await getCollection("posts");
    ---
  2. Dovrai anche aggiornare i riferimenti ai dati restituiti per ogni post. Ora troverai i valori del frontmatter sulla proprietà data di ogni oggetto. Inoltre, quando si usano le collezioni, ogni oggetto post avrà uno slug di pagina, non un URL completo.

    src/pages/blog.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../layouts/BaseLayout.astro";
    import BlogPost from "../components/BlogPost.astro";
    const pageTitle = "My Astro Learning Blog";
    const allPosts = await getCollection("posts");
    ---
    <BaseLayout pageTitle={pageTitle}>
    <p>This is where I will post about my journey learning Astro.</p>
    <ul>
    {
    allPosts.map((post) => (
    <BlogPost url={post.url} title={post.frontmatter.title} />)}
    <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />
    ))
    }
    </ul>
    </BaseLayout>
  3. Il blog di tutorial genera anche dinamicamente una pagina per ogni tag usando src/pages/tags/[tag].astro e visualizza un elenco di tag su src/pages/tags/index.astro.

    Applica gli stessi cambiamenti di cui sopra a questi due file:

    • recupera i dati per tutti i posts del tuo blog usando getCollection("posts") invece di Astro.glob()
    • accedi a tutti i valori di frontmatter usando data invece di frontmatter
    • crea un URL della pagina aggiungendo lo slug del post al percorso /posts/

    La pagina che genera individualmente le pagine dei tag diventa ora:

    src/pages/tags/[tag].astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../../layouts/BaseLayout.astro";
    import BlogPost from "../../components/BlogPost.astro";
    export async function getStaticPaths() {
    const allPosts = await getCollection("posts");
    const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
    return uniqueTags.map((tag) => {
    const filteredPosts = allPosts.filter((post) =>
    post.data.tags.includes(tag)
    );
    return {
    params: { tag },
    props: { posts: filteredPosts },
    };
    });
    }
    const { tag } = Astro.params;
    const { posts } = Astro.props;
    ---
    <BaseLayout pageTitle={tag}>
    <p>Posts tagged with {tag}</p>
    <ul>
    { posts.map((post) => <BlogPost url={`/posts/${post.slug}/`} title={post.data.title} />) }
    </ul>
    </BaseLayout>

    Prova tu - Aggiorna la query nella pagina dell’indice dei tag

    Sezione intitolata Prova tu - Aggiorna la query nella pagina dell’indice dei tag

    Importa e usa getCollection per recuperare i tag usati nei post del blog su src/pages/tags/index.astro, seguendo gli stessi passaggi di cui sopra.

    Mostrami il codice.
    src/pages/tags/index.astro
    ---
    import { getCollection } from "astro:content";
    import BaseLayout from "../../layouts/BaseLayout.astro";
    const allPosts = await getCollection("posts");
    const tags = [...new Set(allPosts.map((post) => post.data.tags).flat())];
    const pageTitle = "Tag Index";
    ---
    ...

Aggiorna ogni valore di frontmatter per corrispondere allo schema

Sezione intitolata Aggiorna ogni valore di frontmatter per corrispondere allo schema
  1. Se necessario, aggiorna qualunque valore del frontmatter in tutto il tuo progetto, come nel tuo layout, che non corrisponde allo schema delle collezioni.

    Nel blog di esempio, pubDate era una stringa. Ora, secondo lo schema che definisce i tipi per il frontmatter del post, pubDate sarà un oggetto Date.

    Per renderizzare la data nel layout del post del blog, convertila in una stringa:

    src/layouts/MarkdownPostLayout.astro
    ...
    <BaseLayout pageTitle={frontmatter.title}>
    <p>{frontmatter.pubDate.toString().slice(0,10)}</p>
    <p><em>{frontmatter.description}</em></p>
    <p>Written by: {frontmatter.author}</p>
    <img src={frontmatter.image.url} width="300" alt={frontmatter.image.alt} />
    ...
  1. Per ultima cosa, il progetto di blog tutorial include un feed RSS. Questa funzione deve anche usare getCollection() per restituire informazioni dai tuoi post del blog. Poi genererai gli elementi RSS usando l’oggetto data restituito.

    src/pages/rss.xml.js
    import rss from '@astrojs/rss';
    import { pagesGlobToRssItems } from '@astrojs/rss';
    import { getCollection } from 'astro:content';
    export async function GET(context) {
    const posts = await getCollection("posts");
    return rss({
    title: 'Astro Learner | Blog',
    description: 'My journey learning Astro',
    site: context.site,
    items: await pagesGlobToRssItems(import.meta.glob('./**/*.md')),
    items: posts.map((post) => ({
    title: post.data.title,
    pubDate: post.data.pubDate,
    description: post.data.description,
    link: `/posts/${post.slug}/`,
    })),
    customData: `<language>en-us</language>`,
    })
    }

Per l’esempio completo della guida al blog usando le collezioni di contenuto, vedi il branch Content Collections del repo della guida.