- 起步
- 核心概念
- 教程
- 基础内容
- 内置功能
- 集成
- 操作指南
- 使用指南
- 配置
- 参考
- 社区资源
- 其他
- 为文档做出贡献
- 手动安装 Astro
- 升级到 Astro v4
- 升级到 Astro v3
- 升级到 Astro v2
- Legacy v0.x Upgrade Guide
- 从 Create React App(CRA)迁移
- 关于本教程
- 第一单元:前期准备
- 准备开发环境
- 创建你的第一个 Astro 项目
- 你的第一行 Astro 代码
- 创建在线代码仓库
- 将你的网站部署到网络
- 第二单元:页面
- 创建你的第一个 Astro 页面
- 编写你的第一篇 Markdown 博客文章
- 添加「关于你」的动态内容
- 给你的「关于」页面添加样式
- 应用全局样式
- 第三单元:组件
- 创建一个可重复使用的导航组件
- 创建社交媒体 footer
- 自己动手搭建导航 Header
- 编写你的第一个浏览器脚本
- 第四单元:布局
- 编写你的第一个布局
- 创建并传递数据到博客布局
- 布局结合,两全其美
- 第五单元 - Astro API
- 创建文章存档页
- 生成标签页面
- 编写标签索引页面
- 添加 RSS 订阅源
- 第六单元 - Astro 群岛
- 搭建你的第一个 Astro 岛屿
- 回到干燥的陆地。让你的博客从白天到黑夜,无需岛屿!
- 恭喜你!
- @astrojs/mdx
- 添加阅读时间
- 创建开发者工具栏应用
- @astrojs/alpinejs
- @astrojs/lit
- @astrojs/preact
- @astrojs/react
- @astrojs/solid-js
- @astrojs/svelte
- @astrojs/vue
- @astrojs/cloudflare
- @astrojs/netlify
- @astrojs/node
- @astrojs/vercel
- @astrojs/db
- @astrojs/markdoc
- @astrojs/partytown
- @astrojs/sitemap
- @astrojs/tailwind
- 使用流式处理来提升页面性能
- 从 Gatsby 迁移
- 从 Next.js 迁移
- 从 NuxtJS 迁移
- 从 Docusaurus 迁移到 Astro
- 从 Eleventy 迁移到 Astro
- 从 GitBook 迁移到 Astro
- 从Gridsome迁移到Astro
- 从 Hugo 迁移
- 从 Jekyll 迁移
- 从 Pelican 迁移
- 从 SvelteKit 迁移
- 从VuePress迁移
- 从 WordPress 迁移
- 状态共享
- Storyblok 与 Astro
- Contentful 与 Astro
- ButterCMS & Astro
- Builder.io & Astro
- Cosmic 与 Astro
- DatoCMS 与 Astro
- Front Matter CMS 与 Astro
- Ghost & Astro
- Hashnode & Astro
- Hygraph 与 Astro
- Keystatic & Astro
- Kontent.ai 与 Astro
- 无头模式的 Statamic 与 Astro
- Strapi 与 Astro
- Tina CMS 与 Astro
- Umbraco & Astro
- 无头(headless)模式的 WordPress 与 Astro
- ApostropheCMS 与 Astro
- Caisy & Astro
- CloudCannon与Astro
- Crystallize 与 Astro
- Decap CMS 与 Astro
- Directus 与 Astro
- KeystoneJS 与 Astro
- microCMS & Astro
- Payload CMS 与 Astro
- Prepr CMS & Astro
- Prismic & Astro
- Sanity & Astro
- Sitecore 体验管理器 & Astro
- Spinal & Astro
- 创作内容
- Firebase 与 Astro
- Supabase 与 Astro
- Turso 和 Astro
- Xata 与 Astro
- Appwrite & Astro
- 部署你的 Astro 站点至 Netlify
- 部署你的 Astro 站点至 Vercel
- 如何将你的 Astro 网站部署到 Deno
- 部署你的 Astro 站点至 GitHub Pages
- 部署你的 Astro 站点至 GitLab Pages
- 部署你的 Astro 站点至 Cloudflare Pages
- 将你的 Astro 网站部署到 AWS
- 将你的 Astro 网站通过 Flightcontrol 部署到 AWS
- 将你的 Astro 网站通过 SST 部署到 AWS
- 将你的 Astro 网站部署至 Google Cloud
- 部署你的 Astro 站点至 Google Firebase 托管
- 将你的 Astro 网站部署到 Heroku
- 将你的 Astro 网站部署到 Microsoft Azure
- 部署你的 Astro 站点至 Buddy
- 将你的 Astro 网站部署到 Edgio
- 将你的 Astro 站点部署到 Fly.io
- 将你的 Astro 网站部署到 Render
- 将你的 Astro 网站部署到 Stormkit
- 将你的 Astro 网站部署到 Surge
- 通过 Cleavr 部署你的 Astro 网站
- 将你的 Astro 站点部署到 Kinsta 应用托管
- 将你的 Astro 网站部署到 Space
- 将你的 Astro 站点部署到 Zeabur
- 将你的 Astro 网站部署到 Zerops
- 添加 RSS 摘要
- 安装一个 Vite 或 Rollup 插件
- 构建自定义图像组件
- 使用 API 路由构建表单
- 在 Astro 页面中构建 HTML 表单
- 在 Astro 中使用 Bun
- 调用服务器端点
- 校验验证码
- 用 Docker 来构建你的 Astro 网站
- 动态导入图片
- 为链接添加图标
- 添加 i18n 功能
- 添加最后修改时间
- 在 Astro 组件中共享状态
- 使用 Tailwind Typography 美化渲染后的 Markdown
- Unknown compiler error.
- Astro.redirect is not available in static mode.
- Astro.clientAddress is not available in current adapter.
- Astro.clientAddress cannot be used inside prerendered routes.
- Astro.clientAddress is not available in static mode.
- No static path found for requested path.
- Invalid type returned by Astro page.
- Missing value for client:media directive.
- No matching renderer found.
- No client entrypoint specified in renderer.
- Missing hint on client:only directive.
- Invalid value returned by a getStaticPaths path.
- Invalid entry inside getStaticPath's return value
- Invalid value returned by getStaticPaths.
- getStaticPaths RSS helper is not available anymore.
- Missing params property on getStaticPaths route.
- Invalid value for getStaticPaths route parameter.
- getStaticPaths() function required for dynamic routes.
- Invalid slot name.
- Cannot use Server-side Rendering without an adapter.
- No import found for component.
- Invalid prerender export.
- Invalid component arguments.
- Page number param not found.
- Image missing required "alt" property.
- Error while loading image service.
- Missing image dimensions
- Failed to retrieve remote image dimensions
- Unsupported image format
- Unsupported image conversion
- Prerendered dynamic endpoint has path collision.
- Expected src to be an image.
- Expected image options.
- Cannot set both densities and widths
- Image not found.
- Could not process image metadata.
- Image not found.
- Could not transform image.
- Unable to set response.
- The middleware didn't return a Response.
- The middleware returned something that is not a Response object.
- The endpoint did not return a Response.
- Value assigned to locals is not accepted.
- Astro.response.headers must not be reassigned.
- Can't load the middleware.
- Local images must be imported.
- Astro.glob() used outside of an Astro file.
- Astro.glob() did not match any files.
- A redirect must be given a location with the Location header.
- Invalid dynamic route.
- Could not find Sharp.
- Unknown Vite Error.
- Could not import file.
- Invalid glob pattern.
- Astro couldn't find the correct page to render
- The provided locale does not exist.
- Index page not found.
- You can't use the current function with the current strategy
- Prerendered routes aren't supported when internationalization domains are enabled.
- 启用了手动国际化路由但没有提供中间件。
- Astro can't render the route.
- Unhandled rejection
- i18n Not Enabled
- Route not found.
- Unknown CSS Error
- CSS Syntax Error
- Unknown Markdown Error.
- Failed to parse Markdown frontmatter.
- Invalid frontmatter injection.
- MDX integration missing.
- Unknown configuration error.
- Specified configuration file not found.
- Legacy configuration detected.
- Unknown CLI Error.
- Failed to generate content types.
- Unknown Content Collection Error.
- Content entry frontmatter does not match schema.
- Invalid content entry slug.
- Content Schema should not contain slug.
- Collection does not exist
- Content and data cannot be in same collection.
- Collection contains entries of a different type.
- Data collection entry failed to parse.
- Duplicate content entry slug.
- Actions must be used with server output.
- Unsupported transform in content config.
Strapi 与 Astro
Strapi 是一个开源的、可定制化的无头 CMS。
与 Astro 集成
这个指南将构建一个包装函数,用于连接 Strapi 和 Astro。
前期准备
在开始之前,你需要准备以下内容:
- Astro 项目 - 如果你还没有 Astro 项目,我们的安装指南将帮助你快速入门;
- Strapi CMS 服务器 - 你可以在本地环境中设置 Strapi 服务器。
在 .env
文件中添加 Strapi URL
为了将 Strapi URL 添加到 Astro 中,你可以在项目的根目录中创建一个 .env
文件(如果还没有的话),并添加以下变量:
STRAPI_URL="http://127.0.0.1:1337" // 或者使用你的 IP 地址
重启开发服务器以在你的 Astro 项目中使用这个环境变量。
如果你希望为环境变量使用 IntelliSense,可以在 src/
目录下创建一个 env.d.ts
文件,并像这样配置 ImportMetaEnv
:
interface ImportMetaEnv {
readonly STRAPI_URL: string;
}
你的根目录现在应该包含了新的文件:
文件夹src/
- env.d.ts
- .env
- astro.config.mjs
- package.json
创建 API 包装器
在 src/lib/strapi.ts
中创建一个新文件,并添加以下包装函数来与 Strapi API 进行交互:
interface Props {
endpoint: string;
query?: Record<string, string>;
wrappedByKey?: string;
wrappedByList?: boolean;
}
/**
* Fetches data from the Strapi API
* @param endpoint - The endpoint to fetch from
* @param query - The query parameters to add to the url
* @param wrappedByKey - The key to unwrap the response from
* @param wrappedByList - If the response is a list, unwrap it
* @returns
*/
export default async function fetchApi<T>({
endpoint,
query,
wrappedByKey,
wrappedByList,
}: Props): Promise<T> {
if (endpoint.startsWith('/')) {
endpoint = endpoint.slice(1);
}
const url = new URL(`${import.meta.env.STRAPI_URL}/api/${endpoint}`);
if (query) {
Object.entries(query).forEach(([key, value]) => {
url.searchParams.append(key, value);
});
}
const res = await fetch(url.toString());
let data = await res.json();
if (wrappedByKey) {
data = data[wrappedByKey];
}
if (wrappedByList) {
data = data[0];
}
return data as T;
}
该函数需要一个具有以下属性的对象:
endpoint
- 要获取的端点;query
- 要添加到 URL 末尾的查询参数;wrappedByKey
- 用于包装你Response
对象中的data
键;wrappedByList
- 一个参数,用于“解封”Strapi 返回的列表,并只返回第一项。
可选:创建 Article 接口
如果你使用 TypeScript,可以基于以下 Article 接口来创建 src/interfaces/article.ts
,用于响应 Strapi 的内容类型:
export default interface Article {
id: number;
attributes: {
title: string;
description: string;
content: string;
slug: string;
createdAt: string;
updatedAt: string;
publishedAt: string;
};
}
文件夹src/
文件夹interfaces/
- article.ts
文件夹lib/
- strapi.ts
- env.d.ts
- .env
- astro.config.mjs
- package.json
展示文章列表
更新你的首页
src/pages/index.astro
,用以展示一个博客文章列表,当中的每篇文章都有描述和链接到自己页面。导入包装函数和接口。添加以下 API 调用来获取你的文章并返回一个列表:
src/pages/index.astro--- import fetchApi from '../lib/strapi'; import type Article from '../interfaces/article'; const articles = await fetchApi<Article[]>({ endpoint: 'articles', // 需要获取的内容类型 wrappedByKey: 'data', // 在响应中被拆封的键 }); ---
该 API 调用请求会从
http://localhost:1337/api/articles
获取数据,并返回articles
,这是一个表示数据的 JSON 对象数组:[ { id: 1, attributes: { title: "What's inside a Black Hole", description: 'Maybe the answer is in this article, or not...', description: "Maybe the answer is in this article, or not...", content: "Well, we don't know yet...", slug: 'what-s-inside-a-black-hole', createdAt: '2023-05-28T13:19:46.421Z', updatedAt: '2023-05-28T13:19:46.421Z', publishedAt: '2023-05-28T13:19:45.826Z' slug: "what-s-inside-a-black-hole", createdAt: "2023-05-28T13:19:46.421Z", updatedAt: "2023-05-28T13:19:46.421Z", publishedAt: "2023-05-28T13:19:45.826Z" } }, // ... ]
使用 API 返回的
src/pages/index.astroarticles
数组中的数据,并在列表中展示你的 Strapi 博客文章。这些文章将链接到它们各自的页面,在下一步中你将创建这些页面。--- import fetchApi from '../lib/strapi'; import type Article from '../interfaces/article'; const articles = await fetchApi<Article[]>({ endpoint: 'articles?populate=image', wrappedByKey: 'data', }); --- <!DOCTYPE html> <html lang="en"> <head> <title>Strapi & Astro</title> </head> <body> <main> <ul> { articles.map((article) => ( <li> <a href={`/blog/${article.attributes.slug}/`}> {article.attributes.title} </a> </li> )) } </ul> </main> </body> </html>
生成文章页面
创建文件 src/pages/blog/[slug].astro
来为每篇文章动态生成页面。
文件夹src/
文件夹interfaces/
- article.ts
文件夹lib/
- strapi.ts
文件夹pages/
- index.astro
文件夹blog/
- [slug].astro
- env.d.ts
- .env
- astro.config.mjs
- package.json
静态网站生成
在 Astro 的默认静态模式(SSG)中,使用 getStaticPaths()
从 Strapi 获取文章列表。
---
import fetchApi from '../../lib/strapi';
import type Article from '../../interfaces/article';
export async function getStaticPaths() {
const articles = await fetchApi<Article[]>({
endpoint: 'articles',
wrappedByKey: 'data',
});
return articles.map((article) => ({
params: { slug: article.attributes.slug },
props: article,
}));
}
type Props = Article;
const article = Astro.props;
---
接着,使用每个文章对象的属性来创建每个页面的模板。
"src/pages/blog/[slug].astro---
import fetchApi from '../../lib/strapi';
import type Article from '../../interfaces/article';
export async function getStaticPaths() {
const articles = await fetchApi<Article[]>({
endpoint: 'articles',
wrappedByKey: 'data',
});
return articles.map((article) => ({
params: { slug: article.attributes.slug },
props: article,
}));
}
type Props = Article;
const article = Astro.props;
---
<!DOCTYPE html><html lang="en"> <head> <title>{article.attributes.title}</title> </head>
<body> <main> <img src={import.meta.env.STRAPI_URL + article.attributes.image.data.attributes.url} />
<h1>{article.attributes.title}</h1>
<!-- 渲染纯文本 --> <p>{article.attributes.content}</p> <!-- 渲染 Markdown --> <MyMarkdownComponent> {article.attributes.content} </MyMarkdownComponent> <!-- 渲染 HTML --> <Fragment set:html={article.attributes.content} /> </main> </body></html>
服务器端渲染
如果你选择了 SSR 模式 并设置了 output: server
或 output: hybrid
,那么可以使用以下代码来生成你的动态路由。
创建 src/pages/blog/[slug].astro
文件:
---
import fetchApi from '../../../lib/strapi';
import type Article from '../../../interfaces/article';
const { slug } = Astro.params;
let article: Article;
try {
article = await fetchApi<Article>({
endpoint: 'articles',
wrappedByKey: 'data',
wrappedByList: true,
query: {
'filters[slug][$eq]': slug || '',
},
});
} catch (error) {
return Astro.redirect('/404');
}
---
<!DOCTYPE html>
<html lang="en">
<head>
<title>{article.attributes.title}</title>
</head>
<body>
<main>
<img src={import.meta.env.STRAPI_URL + article.attributes.image.data.attributes.url} />
<h1>{article.attributes.title}</h1>
<!-- 渲染纯文本 -->
<p>{article.attributes.content}</p>
<!-- 渲染 Markdown -->
<MyMarkdownComponent>
{article.attributes.content}
</MyMarkdownComponent>
<!-- 渲染 HTML -->
<Fragment set:html={article.attributes.content} />
</main>
</body>
</html>
这个文件将从 Strapi 获取并呈现与动态的 slug
参数相匹配的页面数据。
由于你在将重定向到 /404
,请在 src/pages
中创建一个 404 页面:
<html lang="en">
<head>
<title>Not found</title>
</head>
<body>
<p>Sorry, this page does not exist.</p>
<img src="https://http.cat/404" />
</body>
</html>
如果找不到文章,用户将被重定向到这个 404 页面,并会收到来自一只可爱猫猫的问候。
发布你的网站
要部署你的网站,请访问我们的部署指南,并按照你偏好的托管提供商的说明操作。
当内容发生变化时重新构建
如果你的项目使用 Astro 的默认静态模式,你需要设置一个 Webhook,在内容发生变化时触发新的构建。如果你使用 Netlify 或 Vercel 作为托管提供商,你可以使用其 Webhook 功能从 Strapi 触发新的构建。
Netlify
在 Netlify 中设置 Webhook:
进入你的网站控制面板,点击 Build & deploy;
在 Continuous Deployment 标签下,找到 Build hooks 部分,点击 Add build hook;
为你的 Webhook 提供一个名称,并选择要触发构建的分支。点击 Save 并复制生成的 URL。
Vercel
在 Vercel 中设置 Webhook:
进入你的项目控制面板,点击 Settings;
在 Git 标签下,找到 Deploy Hooks 部分;
为你的 Webhook 提供一个名称和要触发构建的分支。点击 Add 并复制生成的 URL。
在 Strapi 中添加 Webhook
按照Strapi Webhook 指南在 Strapi 管理面板中创建一个 Webhook。
官方资源
- Strapi 提供的用于 React 的博客指南
更多 CMS 指南
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论