为什么?
自从我开始写博客以来,我想在我的个人网站thomasledoux.be上这样做。
由于在remix&next.js中设置Markdown/MDX支持似乎很困难(我以前为我的网站使用的两个框架),因此我选择在dev.to上写我的博客。
一段时间的运行良好,但是现在我想对博客的布局,分析和获得MDX支持更多。
因此,我开始构建自己的博客平台,然后选择使用Astro!
如何?
设置Astro
设置Astro非常简单。
您可以在终端中运行npm create astro@latest
,按照步骤操作,然后将项目启动并在几秒钟内运行。
一旦您的Astro Project设置了,我们将要做的接下来是添加MDX支持。
您可以通过Astro中的Integration添加MDX支持。
这就像在终端中运行npx astro add mdx
一样容易。
创建MDX博客
安装了MDX集成后,您可以在应用程序中使用MDX组件和页面。
您可以通过在/src/pages
文件夹中添加文件夹/blog
开始。
在此文件夹中,您可以创建您的.mdx
文件,例如best-features-nextjs-conf-2021.mdx
。
在MDX文件的顶部,您可以添加frontmatter
属性。
您可以设置一个layout
,这将使您的博客内容在给定的layout
内部呈现。
在frontmatter
属性中,您还可以添加自定义属性,例如title
,date
,tags
,...
这看起来像:
---
title: "'The 3 best features announced at Next.js Conf 2021';"
layout: '../../layouts/BlogLayout.astro';
tags: ['nextjs', 'javascript'];
date: '2021-06-15T15:14:39.004Z';
---
当您在另一个组件/页面中导入MDX组件/页面时,或使用Astro.glob()
从文件系统读取MDX文件时。
您可以使用此博客概述页面显示标题,创建日期和博客中的标签。
---
let posts = await Astro.glob('./*.mdx');
/* output:
[
{
title: 'The 3 best features announced at Next.js Conf 2021',
layout: '../../layouts/BlogLayout.astro',
tags: ['nextjs', 'javascript'],
date: '2021-06-15T15:14:39.004Z'
}
]
*/
---
<section>
{
posts.map(post => (
<article>
{post.frontmatter.title} - {post.frontmatter.title}
<div class="flex gap-x-4">
{post.frontmatter.tags.map(tag => (
<span>{tag}</span>
))}
</div>
</article>
))
}
</section>
为博客文章添加阅读时间
Astro使您可以轻松地将Remark或Rehype插件添加到您的降价中。
您可以将markdown
属性添加到astro配置文件,将功能/插件添加到remarkPlugins
属性(添加extendDefaultPlugins
属性以确保默认插件不会被此配置更改覆盖):
)
import { remarkReadingTime } from './src/utils/calculate-reading-time.mjs';
export default defineConfig({
integrations: [mdx()],
markdown: {
remarkPlugins: [remarkReadingTime],
extendDefaultPlugins: true,
},
});
./src/utils/calculate-reading-time.mjs
文件看起来像这样:
import getReadingTime from 'reading-time';
import { toString } from 'mdast-util-to-string';
export function remarkReadingTime() {
return function (tree, { data }) {
const textOnPage = toString(tree);
const readingTime = getReadingTime(textOnPage);
// readingTime.text will give us minutes read as a friendly string,
// i.e. "3 min read"
data.astro.frontmatter.minutesRead = readingTime.text;
};
}
因此,您将使用2个外部库reading-time
和mdast-util-to-string
进行此工作。不要忘记对这些!
将其添加到Astro配置中,使此数据可在所有MDX文件的frontmatter
中可用。
您现在可以在我们的博客概述中开始使用此信息:
<section>
{
posts.map(post => (
<article>
<h2>
{post.frontmatter.title} - {post.frontmatter.date}
</h2>
<div class="flex gap-x-4">
{post.frontmatter.tags.map(tag => (
<span>{tag}</span>
))}
</div>
<p>{post.frontmatter.minutesRead}ing time</p>
</article>
))
}
</section>
设置SEO(元标记,OG:图像)
因为我们定义了要在MDX页面上使用的layout
,因此我们可以开始使用layout
内的MDX页面的frontmatter
属性,因为它们已通过Astro.props
对象传递。
然后可以使用这些frontmatter
属性来添加诸如<title>
和og之类的东西:image <meta>
tag:
---
const { frontmatter } = Astro.props;
---
<head>
<title>{frontmatter.title}</title>
<meta content={frontmatter.title} property="og:title" />
<meta content={frontmatter.title} property="twitter:title" />
<meta name="twitter:card" content="summary_large_image" />
<meta
content={`https://website-thomas.vercel.app/api/og?title=${frontmatter.title}`}
property="og:image"
/>
</head>
请注意,在示例中,我正在使用不同域的API路由,这是因为我使用@vercel/og
软件包来基于我的博客文章的标题来生成og:image
。您可以阅读文档here。
我还根据Vercel提供的示例为背景添加了一些闪光。
og:image
代的代码看起来像这样(在My Next.js site上的Next.js API路由中创建):
我正在使用Inter
字体,因此,如果您也想使用此字体,请务必确保download the font files并将其包含在您的项目中。
import {ImageResponse} from '@vercel/og'
export const config = {
runtime: 'experimental-edge',
}
const font = fetch(new URL('../../assets/Inter.ttf', import.meta.url)).then(
res => res.arrayBuffer(),
)
export default function handler(req) {
const fontData = await font;
try {
const {searchParams} = new URL(req.url)
const hasTitle = searchParams.has('title')
const title = hasTitle
? searchParams.get('title')?.slice(0, 100)
: 'My default title'
return new ImageResponse(
(
<div
style={{
background: 'white',
width: '100%',
height: '100%',
display: 'flex',
textAlign: 'center',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'column',
fontFamily: 'Inter',
backgroundImage:
'radial-gradient(circle at 25px 25px, lightgray 2%, transparent 0%), radial-gradient(circle at 75px 75px, lightgray 2%, transparent 0%)',
backgroundSize: '100px 100px',
}}
>
<div
style={{
width: '80%',
display: 'flex',
flexDirection: 'column',
textAlign: 'center',
alignItems: 'center',
}}
>
<p style={{fontSize: 32}}>Thomas Ledoux's blog</p>
<p style={{fontSize: 64}}>{title}</p>
</div>
</div>
),
{
width: 1200,
height: 600,
fonts: [
{
name: 'Inter',
data: fontData,
style: 'normal',
},
],
},
)
} catch (e) {
console.log(`${e.message}`)
return new Response(`Failed to generate the image`, {
status: 500,
})
}
}
就是这样,我的博客现在托管在我自己的网站上!
去https://www.thomasledoux.be/blog检查一下。
在下一篇博客文章中,我将更深入地了解如何在博客上添加一个用于评论的系统,以及使用Prisma和Planetscale进行DB的分析。