<?xml version="1.0" encoding="UTF-8"?><feed xmlns="http://www.w3.org/2005/Atom"><id>https://blog.tusooa.xyz</id><title>javascript - 何事西风不待人</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><entry><id>https://blog.tusooa.xyz/2020/10/10/Some-multilingual-hacks-on-Hexo/</id><title>Some multilingual hacks on Hexo</title><link rel="alternate" href="https://blog.tusooa.xyz/2020/10/10/Some-multilingual-hacks-on-Hexo/"/><published>2020-10-10T16:55:15.000Z</published><content type="html">&lt;div&gt; &lt;p&gt;I do not know why exactly I am so stubborn to insist on making this
site multilingual, and in a way that you may see multiple languages
at the same time. But it is something.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我自己也不明白为什么我执拗得一定要把这网站做成多语言的，还是叫人
能同时看到多种语言的那种。但聊胜于无吧。&lt;/p&gt; &lt;/div&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;&lt;a href=&quot;#A-weird-thing-about-HexoHexo-的诡异事件&quot;&gt;&lt;span&gt; &lt;span&gt; A weird thing about Hexo &lt;/span&gt;&lt;span&gt; Hexo 的诡异事件 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;div&gt; &lt;p&gt;The &lt;em&gt;first&lt;/em&gt; weird thing I got, when I was trying to figure out
&lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;hexo-theme-next&lt;/a&gt;: sometimes &lt;code&gt;hexo server&lt;/code&gt; gives
the perfect result, but when I &lt;code&gt;hexo generate&lt;/code&gt; or &lt;code&gt;hexo deploy&lt;/code&gt;,
nothing will be correct. Everything is just malformed, and it
does not change even if I &lt;code&gt;hexo clean&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;我在折腾 &lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;hexo-theme-next&lt;/a&gt; 的时候碰到的第一个诡异事件是：
有时候 &lt;code&gt;hexo server&lt;/code&gt; 给出了个无懈可击的结果，但只要一 &lt;code&gt;hexo generate&lt;/code&gt;
或者 &lt;code&gt;hexo deploy&lt;/code&gt;，全完蛋。整个网站看着都非常诡异，甚至我
&lt;code&gt;hexo clean&lt;/code&gt; 了之后也没有丝毫变化。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;After digging a lot into the source code, and enabling &lt;code&gt;--debug&lt;/code&gt;,
I finally found that there are some backup files that are also
processed. And the content of those files &lt;em&gt;does&lt;/em&gt; correspond to
the wrong contents on the site. &quot;Okay,&quot; hereby I say, &quot;this
behaviour is indeed ridiculous.&quot;&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;钻进源码里东张西望了好久，再合着 &lt;code&gt;--debug&lt;/code&gt; 的加成，我终于看到了一些备份文件
也被处理了。而其内容&lt;strong&gt;确然&lt;/strong&gt;是应了网站上有问题的东西。「行吧，」如是我说，
「是事直令人齿冷。」&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;And thus I added the ignore rules to ignore all such files,
and everything is hopefully back in place.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;所以我加了忽略规则来忽略这种文件，世界终于清净了，谢天谢地。&lt;/p&gt; &lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;ignore&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  - &lt;/span&gt;&lt;span&gt;&quot;**/*~&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  - &lt;/span&gt;&lt;span&gt;&quot;**/#*&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  - &lt;/span&gt;&lt;span&gt;&quot;**/.#*&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;&lt;a href=&quot;#NexT-s-language-switcherNexT-的语言切换器&quot;&gt;&lt;span&gt; &lt;span&gt; NexT&apos;s language switcher &lt;/span&gt;&lt;span&gt; NexT 的语言切换器 &lt;/span&gt; &lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;div&gt; &lt;p&gt;That is an even more terrible part that comes in. Yes,
&lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;NexT&lt;/a&gt; comes with such a thing called a
&quot;language switcher,&quot; but it never takes you to a right
place. I cannot even get Hexo generate pages for
different languages, no matter how I change the &lt;code&gt;language&lt;/code&gt;
parameter in &lt;code&gt;_config.yml&lt;/code&gt;. So whenever I click on the
language switcher, I got a 404. And it is hidden at the very
bottom of the page --- How should one expect their visitor
to dig into the deepest hole before they can switch languages?&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;这玩意儿甚至更可怕了。是是是，&lt;a href=&quot;https://github.com/next-theme/hexo-theme-next&quot;&gt;NexT&lt;/a&gt; 有个叫「语言切换器」
的东西，但是它总把人引入歧途。让 Hexo 给不同的语言分别生成页面，这我
怎么改 &lt;code&gt;_config.yml&lt;/code&gt; 里的 &lt;code&gt;language&lt;/code&gt; 参数，也弄不成。所以呢，每次
按下这语言切换器的时候，404 就浮现在我眼前了。而且这切换器给藏在了页面
最底下——让访客钻进最深的洞里才许其切换语言，这能成吗？&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;So, well, since NexT&apos;s language switcher sucks, and multi-page
style multi-language implementation is not feasible, why not just
put everything all together? NexT at least provides a way to
customize what texts are shown... in &lt;code&gt;languages.yml&lt;/code&gt;.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;啊啊，行吧，NexT 这语言切换器是糟透了，多页面显示多语言也办不到，那么把
所有东西全放一起，这又如何呢？NexT 至少给了个用 &lt;code&gt;languages.yml&lt;/code&gt; 来控制
显示什么文字的方法呀......&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;The main idea is to merge NexT&apos;s default translations into one.
I made a Perl script for this. The text for every language is a
&lt;code&gt;span&lt;/code&gt;, and they are next to each other. Use css to put a divider
between every visible &lt;code&gt;span&lt;/code&gt;. Whether a language is shown is controlled
by a JavaScript program that adds or removes classes from the elements.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;大意就是把 NexT 的默认翻译全整一起去。这事我写了个 Perl 脚本去做。每种语言的文字
装在一个 &lt;code&gt;span&lt;/code&gt; 里，并并排。用 css 在每个显示了的 &lt;code&gt;span&lt;/code&gt; 之间，摆一个分割线。
至于某种语言是显示呢是隐藏呢，这让 JavaScript 程序来控制，就从元素里加上或是减去
些 class 就好。&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;As I am too lazy, the code is all &lt;a href=&quot;https://lily-is.land/tusooa/blog&quot;&gt;on GitLab&lt;/a&gt;.
Whether this is a viable implementation is left as an exercise
for the reader.&lt;/p&gt; &lt;/div&gt;
&lt;div&gt; &lt;p&gt;因为我太懒了，代码都在 &lt;a href=&quot;https://lily-is.land/tusooa/blog&quot;&gt;GitLab 上&lt;/a&gt;。这东西到底可行不，
留给读者作练习。&lt;/p&gt; &lt;/div&gt;</content></entry><entry><id>https://blog.tusooa.xyz/2020/10/01/Fix-firefox-address-bar-clickSelectsAll-bug/</id><title>Fix firefox address bar clickSelectsAll bug (Spoiler: no re-compilation required.)</title><link rel="alternate" href="https://blog.tusooa.xyz/2020/10/01/Fix-firefox-address-bar-clickSelectsAll-bug/"/><published>2020-10-01T20:15:56.000Z</published><updated>2026-01-13T12:00:00.000Z</updated><content type="html">&lt;p&gt;This is last updated 2026,1,13 (2) to reflect new changes for Firefox &amp;gt;= 147.
&lt;a href=&quot;https://r.lily-is.land/tusooa/tusooa.pg.kazv.moe/commits/branch/astro/astro/src/content/blog/Fix-firefox-address-bar-clickSelectsAll-bug.md&quot;&gt;View update history&lt;/a&gt;. This post has been updated 4 times to adapt
to upstream changes.&lt;/p&gt;
&lt;p&gt;A couple of months ago, I opened my Firefox as usual, I found out that
when I click on the address bar, it dared to select everything in it
as if any creepy browser would do! The first thing I did is to check
the &lt;code&gt;clickSelectsAll&lt;/code&gt; pref -- what I always do first after getting a
new install of Firefox on Windows is setting this pref to &lt;code&gt;false&lt;/code&gt;,
and setting &lt;code&gt;doubleClickSelectsAll&lt;/code&gt; pref to &lt;code&gt;true&lt;/code&gt;: that is the default
behaviour for Firefox on GNU/Linux... that time at least...&lt;/p&gt;
&lt;p&gt;Much to my disappointment, the pref are setting correctly, but nothing
works. I tried to search for this, but without success, maybe since
this bug was so new, or I was to silly to apply the right keywords
(huh, maybe the latter one?). So I created an account on Mozilla&apos;s
bugtracker just to open &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1629135&quot;&gt;a bug&lt;/a&gt;. At the same time I switched
back to the ESR version of Firefox, which rid me (till recently) of
this stupid address bar but still granted me security updates. A
few days ago, however, Firefox ESR was unfortunately eventually shipped
with this bug, calling for a solution.&lt;/p&gt;
&lt;a&gt;&lt;/a&gt;
&lt;h1&gt;&lt;a href=&quot;#Some-more-background&quot;&gt;Some more background&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Here I will add more background because I need to complain a lot (&amp;gt;w&amp;lt;).
If you would like to see the solution directly, &lt;a href=&quot;#The-solution&quot;&gt;jump there&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Someone on bugzilla pointed out that the bug had been
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1621570&quot;&gt;raised by someone else&lt;/a&gt;. Following that bug, I saw that
the developer was being pretty toxic and just marked it as &lt;code&gt;WONTFIX&lt;/code&gt;,
despite many people criticized the buggy behaviour and regarded
the original behaviour as signature of Firefox. I finally switched
from Ubuntu to Gentoo after the new ESR, as I would like to have more
control of my software.&lt;/p&gt;
&lt;p&gt;Yesterday I &lt;a href=&quot;https://matrix.to/#/!NREUQXSZzhWoQFQpTe:matrix.org/$16014845914171808dKKcm:matrix.org?via=matrix.org&amp;amp;via=tusooa.xyz&quot;&gt;talked&lt;/a&gt; to &lt;a href=&quot;https://outsideofinfinity.wordpress.com/&quot;&gt;tiar&lt;/a&gt; about the freedom
of users to make software behave the way they want, without necessarily
being a developer. I complained that many free/libre software does not
excel in this aspect, using Firefox &amp;gt;=75 as an example.&lt;/p&gt;
&lt;p&gt;The thing Firefox developers does, by removing the &lt;code&gt;clickSelectsAll&lt;/code&gt;
prefs, is actually somewhat limiting users&apos; freedom, as customization
becomes harder and harder. This kind of freedom has been brought up
by a KDE person as &lt;a href=&quot;https://phabricator.kde.org/T11091&quot;&gt;a goal&lt;/a&gt; called &quot;freedom out of the box.&quot;
In short, it aims to make changing the behaviour of a program
as easy as just using it, probably unifying the interface where a program
is used and where a program is customized.&lt;/p&gt;
&lt;p&gt;And that is reasonable: no one should have to spend quite a long time
reading an extraordinarily large code base just to make a tiny little
change that would significantly improve their lives. We will simply not
have that much time. I know tweaking system is fun... (should I say
addictive?) but still, instant result is always a good-to-have.&lt;/p&gt;
&lt;h1&gt;&lt;a href=&quot;#The-solution&quot;&gt;The solution&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;For Firefox, we do have a &lt;a href=&quot;https://superuser.com/questions/540851/go-back-to-not-selecting-the-whole-url-when-i-click-the-address-bar&quot;&gt;solution&lt;/a&gt; without needing to
recompile. That is, to change the &lt;code&gt;omni.ja&lt;/code&gt; pack in the Firefox
distribution. Based on that I managed to restore the old good
urlbar behaviour.&lt;/p&gt;
&lt;p&gt;For my &lt;code&gt;firefox-bin&lt;/code&gt; on Gentoo, the relevant file is at
&lt;code&gt;/opt/firefox/browser/omni.ja&lt;/code&gt;. (In Firefox v146 with &lt;a href=&quot;https://phabricator.services.mozilla.com/D270553#change-373rnO3LTLeb&quot;&gt;https://phabricator.services.mozilla.com/D270553#change-373rnO3LTLeb&lt;/a&gt;, the file was once shortly in &lt;code&gt;omni.ja&lt;/code&gt; instead of &lt;code&gt;browser/omni.ja&lt;/code&gt;.)&lt;/p&gt;
&lt;p&gt;First make a copy of that file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; -v&lt;/span&gt;&lt;span&gt; /opt/firefox/browser/omni.ja&lt;/span&gt;&lt;span&gt; omni.ja.orig&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then unzip the file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;mkdir&lt;/span&gt;&lt;span&gt; omni&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span&gt;unzip&lt;/span&gt;&lt;span&gt; -d&lt;/span&gt;&lt;span&gt; omni&lt;/span&gt;&lt;span&gt; /opt/firefox/browser/omni.ja&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It may return 2, but does not matter.&lt;/p&gt;
&lt;p&gt;Then edit the &lt;code&gt;chrome/browser/content/browser/urlbar/UrlbarInput.mjs&lt;/code&gt;. In the &lt;code&gt;_on_mousedown&lt;/code&gt; function:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Change&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_preventClickSelectsAll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;focused&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;_preventClickSelectsAll&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; true&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to get the (no) &lt;code&gt;clickSelectsAll&lt;/code&gt; behaviour.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;      // Do not suppress the focus border if we are already focused. If we&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // did, we&apos;d hide the focus border briefly then show it again if the&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      // user has Top Sites disabled, creating a flashing effect.&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;view&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;autoOpen&lt;/span&gt;&lt;span&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;, add:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;     // doubleClickSelectsAll&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;     if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;detail&lt;/span&gt;&lt;span&gt; ==&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       this&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;select&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       event&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;preventDefault&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       break&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;to get the &lt;code&gt;doubleClickSelectsAll&lt;/code&gt; behaviour.&lt;/p&gt;
&lt;p&gt;Note that this will &lt;em&gt;not&lt;/em&gt; put the url into primary selection
upon double click. This can be useful sometimes, if you just
would like to replace the current url with the one currently
in primary selection.
If you would like to put the url into primary selection
upon double click, which completely restores the original
behaviour, change &lt;code&gt;this.select();&lt;/code&gt; to &lt;code&gt;this.inputField.select();&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I have also made a patch (command &lt;code&gt;diff -Naru omni-orig omni-new&lt;/code&gt;). &lt;a href=&quot;/code/firefox-no-clickSelectsAll-fix.patch&quot;&gt;Download the patch&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;There is also the search bar to change. The original Superuser answer
suggests this, but as I do not use the search bar, I have not
tried it out, nor do I know what the original behaviour of it was.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;sed&lt;/span&gt;&lt;span&gt; -i&lt;/span&gt;&lt;span&gt; &apos;s/this\._preventClickSelectsAll = this\._textbox\.focused;/this._preventClickSelectsAll = true;/&apos;&lt;/span&gt;&lt;span&gt;  omni/chrome/browser/content/browser/search/searchbar.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After editing, we need to re-pack the files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; omni&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span&gt;zip&lt;/span&gt;&lt;span&gt; -0DXqr&lt;/span&gt;&lt;span&gt; ../omni.ja&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And replace the original one:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;cp&lt;/span&gt;&lt;span&gt; -v&lt;/span&gt;&lt;span&gt; omni.ja&lt;/span&gt;&lt;span&gt; /opt/firefox/browser/omni.ja&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may need to change the ownership of the newly-created archive:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;chown&lt;/span&gt;&lt;span&gt; [U]:[G] /opt/firefox/browser/omni.ja&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;[U]&lt;/code&gt; and &lt;code&gt;[G]&lt;/code&gt; refers to the owner and group of the original
file (we made a backup at &lt;code&gt;omni.ja.orig&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To ensure everything takes effect, make a file called &lt;code&gt;.purgecaches&lt;/code&gt;
to make Firefox aware of the changes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;touch&lt;/span&gt;&lt;span&gt; /opt/firefox/browser/.purgecaches&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Okay, from now on, we shall no longer suffer from the &lt;code&gt;clickSelectsAll&lt;/code&gt;
bug.&lt;/p&gt;
&lt;p&gt;Also, you may want to have additional configurations, such as
&lt;a href=&quot;https://www.userchrome.org/megabar-styling-firefox-address-bar.html&quot;&gt;disabling the pop-up list upon clicking address bar&lt;/a&gt;
or &lt;a href=&quot;https://github.com/WesleyBranton/Remove-Firefox-Megabar/blob/master/remove_megabar.css&quot;&gt;gettind rid of the address bar expanding effect&lt;/a&gt;
when clicked upon.&lt;/p&gt;</content></entry></feed>