<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><id>https://blog.tusooa.xyz</id><title>代码 - 何事西风不待人</title><link href="https://blog.tusooa.xyz"/><subtitle>迷糊萝莉</subtitle><updated>2024-11-07T19:00:00.000Z</updated><entry><id>https://blog.tusooa.xyz/2024/11/07/From-hexo-to-astro/</id><title>From hexo to astro</title><link rel="alternate" href="https://blog.tusooa.xyz/2024/11/07/From-hexo-to-astro/"/><published>2024-11-07T19:00:00.000Z</published><content type="html">&lt;div&gt; &lt;p&gt;I have been using &lt;a href=&quot;https://astro.build&quot;&gt;astro&lt;/a&gt; for this blog for quite a long time now.
I will write here how I migrated from &lt;a href=&quot;https://hexo.io&quot;&gt;hexo&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我现在在这个 blog 用 &lt;a href=&quot;https://astro.build&quot;&gt;astro&lt;/a&gt; 已经挺长时间了。
来写写我怎么从 &lt;a href=&quot;https://hexo.io&quot;&gt;hexo&lt;/a&gt; 迁移的。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;This will not be an introduction to astro. Instead, it covers some major challenges
I faced when I tried to implement in astro the same thing I have in my original hexo blog,
and how I resolved them.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;本文不是对 astro 的介绍。相反地，它包括了一些我试图在 astro 里实现我原来的 hexo
博客里面有的东西的时候遇到的挑战，跟我是怎么解决的。&lt;/p&gt; &lt;/div&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h2&gt;&lt;a href=&quot;#The-start起始&quot;&gt;&lt;span&gt; &lt;span&gt; The start &lt;/span&gt;&lt;span&gt; 起始 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;I used to have a couple of blogs before this one a long time ago using jekyll and wordpress,
but this hexo blog was started in 2019, from the commit log, and I started using &lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;NexT theme&lt;/a&gt;
&lt;sup&gt;&lt;a href=&quot;#user-content-fn-next&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; in 2020. I added &lt;a href=&quot;/2020/10/10/Some-multilingual-hacks-on-Hexo/&quot;&gt;multi-language support&lt;/a&gt; two months later, and it ran for a couple
of years, till the end of 2023, when I read Beiyan Yunyi&apos;s &lt;a href=&quot;https://blog.yunyi.beiyan.us/posts/removeHexo/&quot;&gt;blog post about astro&lt;/a&gt;.
She describes why hexo is frowned upon, and why astro is preferred. Indeed, astro solves some problems
I was facing at that time, for example, I did &lt;a href=&quot;https://github.com/next-theme/hexo-theme-next/pull/243/files#r662300271&quot;&gt;break the theme&lt;/a&gt; by accidentally
removing a closing tag while dealing with conflicts. After researching on it
for quite a while, I finally decided to switch to astro.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我很久以前有过一些用 jekyll 跟 wordpress 的博客，但是根据提交记录看，
这个 hexo 的博客是 2019年开始的。我在 2020年开始用 &lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;NexT主题&lt;/a&gt; &lt;sup&gt;&lt;a href=&quot;#user-content-fn-next&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;。
两个月之后，我添加了&lt;a href=&quot;/2020/10/10/Some-multilingual-hacks-on-Hexo/&quot;&gt;多语言支持&lt;/a&gt;，运行了好几年，
直到 2023年底，我读到北雁云依的&lt;a href=&quot;https://blog.yunyi.beiyan.us/posts/removeHexo/&quot;&gt;关于astro的博客文章&lt;/a&gt;。
她描述了为什么 hexo 让人皱眉，为什么 astro 更好。确实，astro 解决了一些我当时面临的问题，
比如，我之前&lt;a href=&quot;https://github.com/next-theme/hexo-theme-next/pull/243/files#r662300271&quot;&gt;搞坏了主题&lt;/a&gt;，因为我在解决冲突的时候不小心删掉了一个结束标签。
研究了好一会儿之后，我终于决定换到 astro 了。&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#Goals-for-the-migration迁移的目标&quot;&gt;&lt;span&gt; &lt;span&gt; Goals for the migration &lt;/span&gt;&lt;span&gt; 迁移的目标 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;I made several goals for the migration, including:&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我指定了几个迁移的目标，包括：&lt;/p&gt; &lt;/div&gt;
&lt;ul&gt;&lt;li&gt;&lt;span&gt; &lt;span&gt; Multi-language support is retained. &lt;/span&gt;&lt;span&gt; 多语言支持要保留。 &lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt; &lt;span&gt; RSS should work, including tag-specific RSS. &lt;/span&gt;&lt;span&gt; RSS 得工作，包括标签的 RSS。 &lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt; &lt;span&gt; Link-to-link compatibility, including hash routing. &lt;/span&gt;&lt;span&gt; 链接到链接的兼容性，包括 # 后面的东西。 &lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt; &lt;span&gt; Able to work without JavaScript. &lt;/span&gt;&lt;span&gt; 没得 JavaScript 也要能工作。 &lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span&gt; &lt;span&gt; Responsive and convergent. &lt;/span&gt;&lt;span&gt; 要响应式，也得各平台同一。 &lt;/span&gt; &lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h2&gt;&lt;a href=&quot;#Multi-language-support多语言支持&quot;&gt;&lt;span&gt; &lt;span&gt; Multi-language support &lt;/span&gt;&lt;span&gt; 多语言支持 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;This is actually easier than hexo. Just define components. Add proper CSS to it.
No more remembering the template language. Just use MDX/JSX, and it will work.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;这个其实比 hexo 更简单。定义组件就行了。添加对的 CSS。
不用再去记模板语言了。就用 MDX 跟 JSX，就能运作了。&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#Link-compatibility链接兼容性&quot;&gt;&lt;span&gt; &lt;span&gt; Link compatibility &lt;/span&gt;&lt;span&gt; 链接兼容性 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;I want to explain why even I want this. Because the website has been there for quite some time,
and there are already links in the wild leading to existing pages of the blog, and I from time
to time link to my &lt;a href=&quot;/poems/&quot;&gt;poems page&lt;/a&gt;. That page is very long, and each heading links to one poem.
It would be very frustrated if one clicks on the link, but does not get which poem I refer to.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我想解释一下为什么我要这个。因为这个网站在那块好久了，
已经有好多野生的链接指向博客现有的页面了，而且我时不时链接到我的&lt;a href=&quot;/poems/&quot;&gt;诗的页面&lt;/a&gt;。
那个页面非常长，每一个标题指向一首诗。
要是有人点开链接，但又不晓得我指的是哪首诗，那会非常抓狂。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;To achieve page link compatibility, I structure &lt;code&gt;/src/pages&lt;/code&gt; the way exactly same as the original
blog will do (either hexo or NexT theme), so &lt;code&gt;/&lt;/code&gt; for article listing with partial content,
&lt;code&gt;/archives/&lt;/code&gt; for article listing with only titles, appending &lt;code&gt;pages/X/&lt;/code&gt; for pages after the first,
&lt;code&gt;/Y/M/D/filename&lt;/code&gt; for individual posts, and three individual pages: &lt;code&gt;/about/&lt;/code&gt;, &lt;code&gt;/poems/&lt;/code&gt; and &lt;code&gt;/tags/&lt;/code&gt;.
List of tag-associated posts is under &lt;code&gt;/tags/X/&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;为了达成页面链接的兼容性，我把 &lt;code&gt;/src/pages&lt;/code&gt; 构建成了跟原来的博客一模一样的方式（要么是 hexo 的，要么是
NexT 主题的），即：&lt;code&gt;/&lt;/code&gt; 是带片段的文章列表，&lt;code&gt;/archives/&lt;/code&gt; 是只有标题的文章列表，第一页之后加上 &lt;code&gt;pages/X/&lt;/code&gt;，
&lt;code&gt;/Y/M/D/filename&lt;/code&gt; 是一个一个的文章，还有三个单独的页面：&lt;code&gt;/about/&lt;/code&gt;，&lt;code&gt;/poems/&lt;/code&gt; 跟 &lt;code&gt;/tags/&lt;/code&gt;。
有某个标签的文章的列表在 &lt;code&gt;/tags/X/&lt;/code&gt; 底下。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The fact that the first page has no &lt;code&gt;pages/X/&lt;/code&gt; suffix but all others do means that I cannot directly
use astro&apos;s &lt;a href=&quot;https://docs.astro.build/en/guides/routing/#pagination&quot;&gt;built-in pagination support&lt;/a&gt;, because apparently it will generate
&lt;code&gt;pages/1/&lt;/code&gt; for the first page, which is not what I want.
I ended up writing my &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/helpers/pagination.js&quot;&gt;own pagination helpers&lt;/a&gt;.
The main point is to use &lt;code&gt;[...page].astro&lt;/code&gt; as the file name (not &lt;code&gt;[page].astro&lt;/code&gt;),
and use &lt;code&gt;undefined&lt;/code&gt; for &lt;code&gt;params.page&lt;/code&gt; of the first page and &lt;code&gt;&quot;pages/X/&quot;&lt;/code&gt; for the others.
The &lt;code&gt;...&lt;/code&gt; allows you to have &lt;code&gt;/&lt;/code&gt; in the params.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;由于 &lt;code&gt;pages/X/&lt;/code&gt; 在第一页没有，而后面的页都有，我没得办法直接用 astro &lt;a href=&quot;https://docs.astro.build/en/guides/routing/#pagination&quot;&gt;内建的分页支持&lt;/a&gt;，
因为显然它就给第一页生成 &lt;code&gt;pages/1/&lt;/code&gt;，这就不是我想要的了。
我最后写了自己的&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/helpers/pagination.js&quot;&gt;分页助手&lt;/a&gt;。主要是用 &lt;code&gt;[...page].astro&lt;/code&gt; 作为文件名（不是 &lt;code&gt;[page].astro&lt;/code&gt;），
然后把第一页的 &lt;code&gt;params.page&lt;/code&gt; 设成 &lt;code&gt;undefined&lt;/code&gt;，别的页的设成 &lt;code&gt;&quot;pages/X/&quot;&lt;/code&gt;。
&lt;code&gt;...&lt;/code&gt; 允许你在 params 里头有 &lt;code&gt;/&lt;/code&gt;。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;For anchor compatibiliy, I directly used the slugize function by hexo.
Plugging it as a &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/rehypeSlugHexoish.js&quot;&gt;rehype plugin&lt;/a&gt; I made by modifying the official rehype-slug, it just works.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;为了锚点的兼容性，我直接用了 hexo 的 slugize 函数。
把它作为一个 &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/rehypeSlugHexoish.js&quot;&gt;rehype 插件&lt;/a&gt;加入进去（我自己根据官方的 rehype-slug 改的），它就能用了。&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#Index-with-partial-content有部分内容的索引&quot;&gt;&lt;span&gt; &lt;span&gt; Index with partial content &lt;/span&gt;&lt;span&gt; 有部分内容的索引 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;In hexo, the index page has partial content with a &quot;read more&quot; link, and this is achieved
through a comment &lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt; in the post markdown. Two things are needed: first,
obtain the content before the &lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt; comment, and render it on the page;
second, have an element in the rendered post html with the id &lt;code&gt;more&lt;/code&gt; at the place of the comment,
and make a link to &lt;code&gt;#more&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;在 hexo 里头，索引页有一部分内容，还有「阅读更多」的链接，这是通过文章的 markdown 里头的
&lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt; 注释达成的。需要两件事：首先，要获取 &lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt; 注释前头的内容，
并且渲染到页面高头；其次，在文章的 html 里头要有一个 id 是 &lt;code&gt;more&lt;/code&gt; 的项目，正正好好就在那个注释的地方，
然后做一个到 &lt;code&gt;#more&lt;/code&gt; 的链接。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The first one is rather tricky, as it involves one level of indirectness.
astro&apos;s &lt;code&gt;getCollection&lt;/code&gt; gives you an array that you can call the &lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html&quot;&gt;&lt;code&gt;render&lt;/code&gt; function&lt;/a&gt;
of the entries and get a astro component called &lt;code&gt;Content&lt;/code&gt;. Normally, we will use it
directly in the JSX as &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;第一个挺难的，因为涉及一层间接的东西。
astro 的 &lt;code&gt;getCollection&lt;/code&gt; 给你一个数组，可以用元素的 &lt;a href=&quot;https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html&quot;&gt;&lt;code&gt;render&lt;/code&gt; 函数&lt;/a&gt;来获得一个叫 &lt;code&gt;Content&lt;/code&gt;
的 astro 组件。一般来讲，我们会把它直接用在 JSX 里头，用 &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;。&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;render&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;However, this will render the whole post, not allowing us to render only a &lt;em&gt;part&lt;/em&gt; of the post.
On the bright side, astro provides a function that can &lt;a href=&quot;https://docs.astro.build/en/reference/api-reference/#astroslotsrender&quot;&gt;render a &lt;em&gt;slot&lt;/em&gt; to html string&lt;/a&gt;.
This means we can first pass &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt; as a slot of another astro component, and then
get the html string, and manipulate the string directly:&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;然而，这会渲染整个文章，不让我们只渲染文章的&lt;em&gt;一部分&lt;/em&gt;。
但好的地方是，astro 给了一个函数，可以&lt;a href=&quot;https://docs.astro.build/en/reference/api-reference/#astroslotsrender&quot;&gt;把一个 &lt;em&gt;slot&lt;/em&gt; 渲染成 html 字符串&lt;/a&gt;。
这就意味到可以先把 &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt; 作为 slot 传给另一个 astro 组件，然后获取 html 字符串，
再直接操纵字符串：&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// PostExcerpt.astro&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;import&lt;/span&gt;&lt;span&gt; PostExcerptImpl&lt;/span&gt;&lt;span&gt; from&lt;/span&gt;&lt;span&gt; &apos;./PostExcerptImpl.astro&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;post&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;props&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; { &lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; } &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; post&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;render&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;PostExcerptImpl&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &amp;lt;&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;PostExcerptImpl&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// PostExcerptImpl.astro&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; postHtml&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; await&lt;/span&gt;&lt;span&gt; Astro&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;slots&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;render&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&apos;default&apos;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; excerpt&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; getExcerpt&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;postHtml&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;---&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;Fragment&lt;/span&gt;&lt;span&gt; set:html&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;excerpt&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt; /&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; href&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt;(Read more | 阅读全文)&lt;/span&gt;&lt;span&gt;&amp;lt;/&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt; &lt;p&gt;So, how to implement &lt;code&gt;getExcerpt&lt;/code&gt; here? We add a &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/rehypeAddMoreAnchor.js&quot;&gt;rehype plugin&lt;/a&gt;
that finds the &lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt; comment (or &lt;code&gt;{/* more */}&lt;/code&gt; in MDX),
and converts it into &lt;code&gt;&amp;lt;a id=&quot;more&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt; in html, and then find this exact string in html.
Everything before it is the excerpt we are looking for.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;那么，怎么实现 &lt;code&gt;getExcerpt&lt;/code&gt; 呢？添加一个 &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/rehypeAddMoreAnchor.js&quot;&gt;rehype 插件&lt;/a&gt;，寻找 &lt;code&gt;&amp;lt;!-- more --&amp;gt;&lt;/code&gt;
注释（或者，MDX 里头的 &lt;code&gt;{/* more */}&lt;/code&gt;），并且把它转换成 html 里的 &lt;code&gt;&amp;lt;a id=&quot;more&quot;&amp;gt;&amp;lt;/a&amp;gt;&lt;/code&gt;。再在 html
里头找这个字符串就好了。它前面的东西，就是我们要找的片段。&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#RSS&quot;&gt;RSS&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;astro has official support for RSS, but it is very limited. It does not by default
include post content, and it does not support injecting the post content directly
at all. Instead, it &lt;a href=&quot;https://docs.astro.build/en/guides/rss/#including-full-post-content&quot;&gt;recommends users to use &lt;em&gt;another&lt;/em&gt; markdown renderer&lt;/a&gt;
in the RSS. This means you cannot render MDX, JSX, or astro components into the RSS.
This is not acceptable for me, because what I want is to allow people read my blog
directly in the RSS reader.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;astro 官方支持 RSS，但非常有限。它默认不包括文章内容，而且也完全不支持直接插入文章内容。
相反地，它在 RSS 里&lt;a href=&quot;https://docs.astro.build/en/guides/rss/#including-full-post-content&quot;&gt;推荐用户用&lt;em&gt;另一个&lt;/em&gt; markdown 渲染器&lt;/a&gt;。
这就意味到你在 RSS 里头没得办法渲染 MDX，JSX，或者 astro 组件了。
这是不能接受的，因为我想要允许我博客的读者直接在 RSS 阅读器里看它。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;An apparent trick is to use what I have already used for the post excerpt: &lt;code&gt;post.render()&lt;/code&gt; and
&lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;. However, this is only for astro components. Moreover, astro components can currently
be used to generate html outputs -- it adds the doctype header, making it unsuitable for xml outputs.
There is an &lt;a href=&quot;https://github.com/withastro/astro/issues/9489&quot;&gt;issue in astro&lt;/a&gt;, which can be eventually traced to this &lt;a href=&quot;https://github.com/withastro/roadmap/pull/916&quot;&gt;merge request
on Container API&lt;/a&gt;. At the time of writing this post, it is not yet available in astro.
There is also another person&apos;s work on &lt;a href=&quot;https://scottwillsey.com/rss-pt2/&quot;&gt;how to generate RSS for astro&lt;/a&gt;. I think I probably
saw it when I was adding RSS support for this blog, but I eventually took a slightly different approach.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;一个显而易见的技巧是，用我之前用来处理文章节选的 &lt;code&gt;post.render()&lt;/code&gt; 和 &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;。但是，这只能在
astro 组件里用。更何况，astro 组件只能生成 html 输出——它会添加 doctype 头部，所以是不适用于 xml 输出的。
&lt;a href=&quot;https://github.com/withastro/astro/issues/9489&quot;&gt;astro 里有一个 issue&lt;/a&gt; 相关，最终可以追溯到这个&lt;a href=&quot;https://github.com/withastro/roadmap/pull/916&quot;&gt;关于 Container API 的合并请求&lt;/a&gt;。
在写这篇文章的时候，在 astro 里面还并不可用。又有另外一个人做了一些关于&lt;a href=&quot;https://scottwillsey.com/rss-pt2/&quot;&gt;怎么给 astro 生成 RSS&lt;/a&gt; 的工作。
我觉得我当年给这个博客添加 RSS 支持的时候可能看过它，但是我最终采取了一个稍微不一样的方法。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;First, to obtain the post content as html, I added a page in the &lt;code&gt;src/pages/atomRender&lt;/code&gt; directory.
All it does is to get all posts, and &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/atomRender/posts/%5B...slug%5D.astro&quot;&gt;render just the content&lt;/a&gt; of those posts as html. In this way,
the content is available as local files.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;首先，要以 html 的的形式获得文章内容，我在 &lt;code&gt;src/pages/atomRender&lt;/code&gt; 目录底下添加了一个页面。
它做的所有事情就是获得所有的文章，然后&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/atomRender/posts/%5B...slug%5D.astro&quot;&gt;只把这些文章内容渲染&lt;/a&gt;成 html。
这样，内容就以本地文件的形式可用了。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;Second, we generate some metadata for the RSS builder. The metadata should at least include
which posts should be rendered, and the title, date, and anything that you want to include in the
RSS. This is achieved by creating a file called &lt;code&gt;X.js&lt;/code&gt;, where &lt;code&gt;X&lt;/code&gt; is the output file name,
and exporting a function called &lt;code&gt;GET&lt;/code&gt; from the js file. This, of course, does not include
the actual rendered post content, because it is not an astro component, and the &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;
is only available in astro components.
I created two of them, one &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/atomRender/metadata.json.js&quot;&gt;for the whole blog&lt;/a&gt; and one &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/atomRender/tags/%5Btag%5D/metadata.json.js&quot;&gt;for tags&lt;/a&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;其次，给 RSS 构建器生成一些元数据。元数据要至少包括有哪些文章需要被渲染，跟它的标题，日期，
还有你想要在 RSS 里放的任何东西。可以创建一个叫 &lt;code&gt;X.js&lt;/code&gt; 的文件，其中 &lt;code&gt;X&lt;/code&gt; 是输出的文件名，
然后从这个 js 文件里导出一个叫 &lt;code&gt;GET&lt;/code&gt; 的函数。当然了，这个文件当然不会包括文章的实际内容，
因为它不是 astro 组件，而只有 astro 组件里才能用 &lt;code&gt;&amp;lt;Content /&amp;gt;&lt;/code&gt;。
我创建了两个这样的文件，一个&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/pages/atomRender/metadata.json.js&quot;&gt;给整个博客&lt;/a&gt;，另一个[给标签][matadatajsonTag]。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The final step is to combine the metadata and the actual post content after they are all
generated. My approach is to add an astro &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/buildFeed.js&quot;&gt;plugin that builds the RSS&lt;/a&gt; as a hook.
An apparent disadvantage is that it is not built when we are running the local dev server,
and it is not suitable if your site is not statically generated. But for my purpose, it is sufficient.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;最后一步就是在把元数据跟实际文章内容都生成了之后，把它们给组合起来了。
我的方法是添加一个 astro &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/plugins/buildFeed.js&quot;&gt;插件来用钩子构建 RSS&lt;/a&gt;。
一个显然的劣势是，在运行本地开发服务器的时候，RSS 是没得被构建的，
而且如果你的网站不是静态生成的，那它就没得办法用。但是对我来讲，就够了。&lt;/p&gt; &lt;/div&gt;
&lt;h2&gt;&lt;a href=&quot;#Responsive-design-without-JavaScript-requirement不强制要-JavaScript-的响应式设计&quot;&gt;&lt;span&gt; &lt;span&gt; Responsive design without JavaScript requirement &lt;/span&gt;&lt;span&gt; 不强制要 JavaScript 的响应式设计 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;div&gt; &lt;p&gt;The NexT theme of hexo does not actually meet this requirement, because on mobile,
the sidebar is either completely hidden (not convergent) or is only activable via JavaScript.
I want my site to function even without JavaScript (it can still contain JavaScript, but
all functionalities should still be available when it is not available).&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;hexo 的 NexT 主题实际上不满足这个要求，因为在移动端，侧边栏要么是完全隐藏的（各平台不同一），
要么就只能经由 JavaScript 启用。我希望我的站点就算没有 JavaScript 也能工作（它还是可以包括
JavaScript，但所有功能在 JavaScript 不可用的时候仍然应该可用）。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;There are three responsive parts on the site: the navigation bar, the site info panel,
and the table of contents for each page. The &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/styles/global.css#L160&quot;&gt;site info panel&lt;/a&gt; is shown as a sidebar when
the page is wide enough, and at the bottom otherwise. &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/components/Header.astro&quot;&gt;The navigation bar&lt;/a&gt; is
shown horizontally when the page is wide enough, and vertically as a drop-down menu when it is not wide enough.
When JavaScript is available, the drop-down menu is hidden at page load, and shown when the activating
button is clicked. When JavaScript is not available, it is always displayed. The &lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/layouts/BlogPost.astro#L22&quot;&gt;table of contents&lt;/a&gt;
is similar, displaying in the sidebar when the page is wide enough. Otherwise, it is displayed at the top of the
post, collapsed by default if JavaScript is available, and always expanded if JavaScript is not available.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;站点上有三个响应式的部分：导航栏，站点信息面板，和每页的目录。
&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/styles/global.css#L160&quot;&gt;站点信息面板&lt;/a&gt;在页面够宽的时候显示为侧边栏，否则就显示在最底部。
&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/components/Header.astro&quot;&gt;导航栏&lt;/a&gt;要是页面够宽，就显示为横向的列表，不然就显示成竖的下拉菜单。
当 JavaScript 可用的时候，下拉菜单在页面加载的时候是隐藏的，按下激活按钮就会显示。
当 JavaScript 不可用的时候，它就一直都显示了。
&lt;a href=&quot;https://lily-is.land/tusooa/tusooa.pg.kazv.moe/-/blob/81076f111e8edd94ecea6dd90e2a8e1abfa7ac5c/astro/src/layouts/BlogPost.astro#L22&quot;&gt;目录&lt;/a&gt;是类似的，在页面够宽的时候显示在侧边栏里。不然，就显示在文章的最上面，
要是 JavaScript 可用就默认折叠，JavaScript 不可用就一直展开。&lt;/p&gt; &lt;/div&gt;
&lt;figure&gt;&lt;p&gt;&lt;/p&gt;&lt;figcaption&gt;&lt;span&gt; &lt;span&gt; Navigation bar on a wide screen, showing the entries horizontally &lt;/span&gt;&lt;span&gt; 宽屏上的导航栏，横向显示项目 &lt;/span&gt; &lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;p&gt;&lt;/p&gt;&lt;figcaption&gt;&lt;span&gt; &lt;span&gt; Navigation bar on a narrow screen, with a button to toggle the vertical list &lt;/span&gt;&lt;span&gt; 窄屏上的导航栏，有一个按钮来开关纵向列表 &lt;/span&gt; &lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;p&gt;&lt;/p&gt;&lt;figcaption&gt;&lt;span&gt; &lt;span&gt; Navigation bar on a narrow screen, with an always-displayed vertical list when JavaScript is not available &lt;/span&gt;&lt;span&gt; 窄屏上的导航栏，当 JavaScript 不可用时，有一个始终显示的纵向列表 &lt;/span&gt; &lt;/span&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;section&gt;&lt;h2&gt;&lt;a href=&quot;#footnote-label&quot;&gt;Footnotes&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;span&gt; &lt;div&gt; This theme has gone through many forks and has various versions. The linked one is the one I use. &lt;/div&gt;&lt;span&gt; 这个主题经历了很多复刻，有多个版本。链接了的是我当年用的版本。 &lt;/span&gt; &lt;/span&gt;
&lt;a href=&quot;#user-content-fnref-next&quot;&gt;↩&lt;/a&gt;
 
&lt;a href=&quot;#user-content-fnref-next-2&quot;&gt;↩&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content></entry></feed>