- 起步
- 核心概念
- 教程
- 基础内容
- 内置功能
- 集成
- 操作指南
- 使用指南
- 配置
- 参考
- 社区资源
- 其他
- 为文档做出贡献
- 手动安装 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.
Kontent.ai 与 Astro
Kontent.ai 是一个无头 CMS,它允许你以结构化和模块化的方式管理内容,并得到人工智能功能的支持。
与 Astro 集成
在这个部分中,你将使用 Kontent.ai TypeScript SDK 将你的 Kontent.ai 项目连接到 Astro 应用程序。
前期准备
在开始之前,你需要以下内容:
Kontent.ai 项目 - 如果你还没有 Kontent.ai 账号,可以 免费注册 并创建一个新项目。
Delivery API 密钥 - 你需要已发布内容的环境 ID 和用于获取草稿的预览 API 密钥(可选)。这两个密钥位于 Kontent.ai 的 Settings -> API Keys 选项卡中。
设置凭据
为了将你的 Kontent.ai 凭据添加到 Astro,你需要在项目的根目录下创建一个名为 .env
的文件,并添加以下变量:
KONTENT_ENVIRONMENT_ID=YOUR_ENVIRONMENT_ID
KONTENT_PREVIEW_API_KEY=YOUR_PREVIEW_API_KEY
这样,这些环境变量就可以在你的 Astro 项目中使用了。
如果你想要获得这些环境变量的 TypeScript IntelliSense,你可以在 src/
目录下创建一个新的 env.d.ts
文件,并像下面这样配置 ImportMetaEnv
:
interface ImportMetaEnv {
readonly KONTENT_ENVIRONMENT_ID: string;
readonly KONTENT_PREVIEW_API_KEY: string;
}
现在,你的根目录应该包含这些新文件:
文件夹src/
- env.d.ts
- .env
- astro.config.mjs
- package.json
安装依赖
要将 Astro 连接到你的 Kontent.ai 项目,请安装 Kontent.ai TypeScript SDK:
- npm
- pnpm
- Yarn
npm install @kontent-ai/delivery-sdk
pnpm add @kontent-ai/delivery-sdk
yarn add @kontent-ai/delivery-sdk
接下来,在 Astro 项目的 src/lib/
目录中创建一个名为 kontent.ts
的新文件。
import { createDeliveryClient } from "@kontent-ai/delivery-sdk";
export const deliveryClient = createDeliveryClient({
environmentId: import.meta.env.KONTENT_ENVIRONMENT_ID,
previewApiKey: import.meta.env.KONTENT_PREVIEW_API_KEY,
});
该实现将使用 .env
文件中的凭据创建一个新的 DeliveryClient
对象。
最后,你的 Astro 项目的根目录现在应该包含这些新文件:
文件夹src/
文件夹lib/
- kontent.ts
- env.d.ts
- .env
- astro.config.mjs
- package.json
获取数据
现在,DeliveryClient
对象对所有组件都可用了。要获取内容,请使用 DeliveryClient
和方法链来定义你想要的项。以下示例展示了获取博客文章,并将它们的标题渲染为列表的基础代码:
---import { deliveryClient } from "../lib/kontent";
const blogPosts = await deliveryClient .items() .type("blogPost") .toPromise()
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Astro</title>
</head>
<body> <ul> {blogPosts.data.items.map(blogPost => ( <li>{blogPost.elements.title.value}</li> ))} </ul>
</body>
</html>
你可以在 Kontent.ai 文档 中找到更多的查询选项。
使用 Astro 和 Kontent.ai 创建博客
通过上述设置,你现在可以创建一个使用 Kontent.ai 作为内容源的博客。
前期准备
Kontent.ai 项目 - 对于本教程,建议使用一个空白项目。如果你的内容模型中已经有一些内容类型,你可以使用它们,但需要修改代码片段以匹配你的内容模型。
已配置从 Kontent.ai 获取内容的 Astro 项目 - 有关如何设置使用 Kontent.ai 的 Astro 项目的详细信息,请参阅上文。
设置内容模型
在 Kontent.ai 中,转到 Content model 并创建一个新的内容类型,具有以下字段和值:
- Name: Blog Post
- Elements:
- Text field
- Name: Title
- Element Required: yes
- Rich text field
- Name: Teaser
- Element Required: yes
- Allowed in this element: only check Text
- Rich text field
- Name: Content
- Element Required: yes
- Date & time field
- Name: Date
- URL slug field
- Name: URL slug
- Element Required: yes
- Auto-generate from: select “Title”
- Text field
接着,点击 Save Changes。
创建内容
现在,转到 Content & assets 选项卡,并创建一个新的 Blog Post 类型的内容项。使用以下值填写字段:
- Content item name: Astro
- Title: Astro is amazing
- Teaser: Astro is an all-in-one framework for building fast websites faster.
- Content: You can use JavaScript to implement the website functionality, but no client bundle is necessary.
- Date & time: select today
- URL slug: astro-is-amazing
完成后,使用顶部的 Publish 按钮发布博客文章。
注意:在进行下一步之前,你可以随意创建任意数量的博客文章。
在 TypeScript 中生成内容模型
接下来,你将从你的内容模型中生成 TypeScript 类型。
首先,安装 Kontent.ai JS 模型生成器、ts-node 和 dotenv:
- npm
- pnpm
- Yarn
npm install @kontent-ai/model-generator ts-node dotenv
pnpm add @kontent-ai/model-generator ts-node dotenv
yarn add @kontent-ai/model-generator ts-node dotenv
接着,将如下脚本添加到 package.json
中:
{
...
"scripts": {
...
"regenerate:models": "ts-node --esm ./generate-models.ts"
},
}
由于类型需要关于你项目的结构信息,而这些信息在公共 API 中是不暴露的,因此你还需要将一个 Content Management API 密钥添加到 .env
文件中。你可以在 Environment settings -> API keys -> Management API 下生成该密钥。
KONTENT_ENVIRONMENT_ID=YOUR_ENVIRONMENT_ID
KONTENT_PREVIEW_API_KEY=YOUR_PREVIEW_API_KEYKONTENT_MANAGEMENT_API_KEY=YOUR_MANAGEMENT_API_KEY
最后,添加配置用于生成模型的模型生成器脚本 generate-models.ts
:
import { generateModelsAsync, textHelper } from '@kontent-ai/model-generator'
import { rmSync, mkdirSync } from 'fs'
import * as dotenv from 'dotenv'
dotenv.config()
const runAsync = async () => {
rmSync('./src/models', { force: true, recursive: true })
mkdirSync('./src/models')
// 修改对应模型的工作目录
process.chdir('./src/models')
await generateModelsAsync({
sdkType: 'delivery',
apiKey: process.env.KONTENT_MANAGEMENT_API_KEY ?? '',
environmentId: process.env.KONTENT_ENVIRONMENT_ID ?? '',
addTimestamp: false,
isEnterpriseSubscription: false,
})
}
// 自调用的异步函数
;(async () => {
await runAsync()
})().catch(err => {
console.error(err)
throw err
})
现在,你可以执行命令了:
- npm
- pnpm
- Yarn
npm run regenerate:models
pnpm run regenerate:models
yarn run regenerate:models
展示博客文章列表
现在你已经准备好获取一些内容了。进入你想要显示博客文章列表的 Astro 页面,例如 src/pages
目录下的首页 index.astro
。
在 Astro 页面的 frontmatter 中获取所有博客文章:
src/pages/index.astro---
import { deliveryClient } from '../lib/kontent';
import type { BlogPost } from '../models';
import { contentTypes } from '../models/project/contentTypes';
const blogPosts = await deliveryClient
.items<BlogPost>
.type(contentTypes.blog_post.codename)
.toPromise()
---
如果你跳过了模型生成,也可以使用未经类型定义的对象和字符串字面量来定义类型:
const blogPosts = await deliveryClient
.items()
.type("blogPost")
.toPromise()
fetch 调用将返回一个包含所有博客文章的列表的 response
对象,这些内容保存在 data.items
中。在 Astro 页面的 HTML 部分,你可以使用 map()
函数列出所有博客文章:
---
import { deliveryClient } from '../lib/kontent';
import type { BlogPost } from '../models';
import { contentTypes } from '../models/project/contentTypes';
const blogPosts = await deliveryClient
.items<BlogPost>
.type(contentTypes.blogPost.codename)
.toPromise()
---<html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>Astro</title> </head> <body> <h1>Blog posts</h1> <ul> {blogPosts.data.items.map(blogPost => ( <li> <a href={`/blog/${blogPost.elements.url_slug.value}/`} title={blogPost.elements.title.value}> {blogPost.elements.title.value} </a> </li> ))} </ul> </body></html>
生成单个博客文章页面
教程的最后一步是生成详细的博客文章页面。
静态站点生成
在本节中,你将使用 Astro 的 静态 (SSG) 模式。
首先,在 /src/pages/blog/
目录中创建一个名为 [slug].astro
的文件,该文件需要导出一个名为 getStaticPaths
的函数,该函数从 CMS 中收集所有数据:
---
import { deliveryClient } from '../../lib/kontent';
import type { BlogPost } from '../../models';
import { contentTypes } from '../../models/project/contentTypes';
export async function getStaticPaths() {
const blogPosts = await deliveryClient
.items<BlogPost>()
.type(contentTypes.blog_post.codename)
.toPromise()
---
到目前为止,该函数会从 Kontent.ai 获取所有博客文章。而这一代码片段与你在首页使用的代码完全相同。
接下来,该函数必须为每个博客文章导出路径和数据。由于你将文件命名为 [slug].astro
,因此表示 URL slug 的参数被称为 slug
:
---
import { deliveryClient } from '../../lib/kontent';
import type { BlogPost } from '../../models';
import { contentTypes } from '../../models/project/contentTypes';
export async function getStaticPaths() {
const blogPosts = await deliveryClient
.items<BlogPost>()
.type(contentTypes.blog_post.codename)
.toPromise()
return blogPosts.data.items.map(blogPost => ({ params: { slug: blogPost.elements.url_slug.value }, props: { blogPost } }))
}
---
最后一部分是提供 HTML 模板并显示每篇博客文章:
src/pages/blog/[slug].astro---
import { deliveryClient } from '../../lib/kontent';
import type { BlogPost } from '../../models';
import { contentTypes } from '../../models/project/contentTypes';
export async function getStaticPaths() {
const blogPosts = await deliveryClient
.items<BlogPost>()
.type(contentTypes.blog_post.codename)
.toPromise()
return blogPosts.data.items.map(blogPost => ({
params: { slug: blogPost.elements.url_slug.value },
props: { blogPost }
}))
}
const blogPost: BlogPost = Astro.props.blogPost---<html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>{blogPost.elements.title.value}</title> </head> <body> <article> <h1>{blogPost.elements.title.value}</h1> <Fragment set:html={blogPost.elements.teaser.value} /> <Fragment set:html={blogPost.elements.content.value} /> <time>{new Date(blogPost.elements.date.value ?? "")}</time> </body></html>
切换到 Astro 预览以查看渲染的博客文章。默认情况下是:http://localhost:4321/blog/astro-is-amazing/
服务端渲染
如果你选择了 SSR 模式,你将使用动态路由从 Kontent.ai 获取页面数据。
在 /src/pages/blog/
目录下创建一个名为 [slug].astro
的新文件,并添加以下代码。数据获取与之前的用例非常相似,但添加了一个 equalsFilter
,以便根据使用的 URL 找到正确的博客文章:
---
import { deliveryClient } from '../../lib/kontent';
import type { BlogPost } from '../../models';
import { contentTypes } from '../../models/project/contentTypes';
const { slug } = Astro.params
let blogPost: BlogPost;
try {
const data = await deliveryClient
.items<BlogPost>()
.equalsFilter(contentTypes.blog_post.elements.url_slug.codename, slug ?? '')
.type(contentTypes.blog_post.codename)
.limitParameter(1)
.toPromise()
blogPost = data.data.items[0]
} catch (error) {
return Astro.redirect('/404')
}
---
如果你没有使用生成的类型,那么你也可以使用字符串字面量来定义内容项类型和过滤元素的代码名称:
const data = await deliveryClient
.items()
.equalsFilter("url_slug", slug ?? '')
.type("blog_post")
.limitParameter(1)
.toPromise()
最后,添加 HTML 代码来渲染博客文章。这部分与静态站点生成的内容相同:
src/pages/blog/[slug].astro---
import { deliveryClient } from '../../lib/kontent';
import type { BlogPost } from '../../models';
import { contentTypes } from '../../models/project/contentTypes';
const { slug } = Astro.params
let blogPost: BlogPost;
try {
const data = await deliveryClient
.items<BlogPost>()
.equalsFilter(contentTypes.blog_post.elements.url_slug.codename, slug ?? '')
.type(contentTypes.blog_post.codename)
.limitParameter(1)
.toPromise()
blogPost = data.data.items[0]
} catch (error) {
return Astro.redirect('/404')
}
---<html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width" /> <title>{blogPost.elements.title.value}</title> </head> <body> <article> <h1>{blogPost.elements.title.value}</h1> <Fragment set:html={blogPost.elements.teaser.value} /> <Fragment set:html={blogPost.elements.content.value} /> <time>{new Date(blogPost.elements.date.value ?? '')}</time> </body></html>
发布网站
要部署你的网站,请访问 部署指南 并按照你偏好的托管提供商的说明进行操作。
在 Kontent.ai 更改时重新构建
如果你的项目使用 Astro 的默认静态模式,你需要设置一个 Webhook 在你的内容发生更改时触发新的构建。如果你使用的是 Netlify 或 Vercel 作为托管提供商,你可以使用其 Webhook 功能从 Kontent.ai 事件中触发新的构建。
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。
添加 Webhook 到 Kontent.ai
在 Kontent.ai 应用程序 中,转到 Environment settings -> Webhooks。点击 Create new webhook 并为你的新 Webhook 提供一个名称。接着,粘贴你从 Netlify 或 Vercel 复制的 URL,并选择哪些事件应触发 Webhook。默认情况下,为了在发布的内容发生更改时重新构建你的网站,你只需要在 Delivery API triggers 下选择 Publish 和 Unpublish 事件。完成后,点击保存。
现在,每当你在 Kontent.ai 中发布一篇新博客文章时,就会触发新的构建,并更新你的博客。
更多 CMS 指南
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论