学习开发astro博客后台(一)钩子文学

发布时间:
更新时间:
👀 阅读量:

前端会点,后端不怎么会,想着 Astro 默认作为 SSG 前端框架,得需要一个伪后台。我看了官方文档,有很多后台,但都不是我想要的那种 dev 开发环境下的后台,所以我准备手搓一个解耦的后台实现,也就是作为 npm 包来分发。

当然回过头来,我还什么都不会,所以从官方文档,从头开始。

钩子

很详细啊,难得官方有中文文档,赞👍,虽然我不太懂钩子,但是不懂就学嘛,还是挺有意思的。

创建项目

Terminal window
npm init

创建 package.json 文件。

安装必要的依赖

安装前置,相关依赖,配置一下命令,方便编译成 JS:

package.json
...
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./src/pages/admin.astro": "./src/pages/admin.astro"
},
"files": [
"dist",
"src/pages",
"README.md"
],
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"clean": "rimraf dist",
"prebuild": "npm run clean",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"typescript": "^5.8.3"
},
"peerDependencies": {
"astro": "^5.8.0"
},
...

基本构建:

终端
D:\test\locastrol> bun run build
$ bun run clean
$ rimraf dist
$ tsc

测试

src/index.ts
import { AstroIntegration } from 'astro';
interface Options{
collections: String;
}
export function locastrol(config: Options = { collections: '' }): AstroIntegration {
const { collections } = config;
return {
name: 'locastrol',
hooks: {
'astro:config:setup': ({ injectRoute,updateConfig,command }) => {
if(command=='dev'){
// 通过 Vite 环境变量传递 collections 参数
updateConfig({
vite: {
define: {
'import.meta.env.LOCASTROL_COLLECTIONS': JSON.stringify(collections)
}
}
}); // 后台首页
// 编辑器路由 - 使用动态路由
injectRoute({
pattern: '/locastrol/editor',
entrypoint: 'locastrol/src/pages/index.astro'
});
injectRoute({
pattern: '/locastrol/editor/[slug]',
entrypoint: 'locastrol/src/pages/[slug].astro'
});
// API 路由
injectRoute({
pattern: '/api/locastrol/posts/[slug]',
entrypoint: 'locastrol/src/api/posts/[slug].ts'
});
injectRoute({
pattern: '/api/locastrol/posts',
entrypoint: 'locastrol/src/api/posts.ts'
});
}
},
'astro:server:start': ({ address }) => {
console.log('\x1b[43m\x1b[30m%s\x1b[0m \x1b[36m%s\x1b[0m', '✅Locastrol后台已经启动', `http://localhost:${address.port}/locastrol/editor`);
},
},
};
}
export type { Options };

终端
cd d:\test\astrotest && New-Item -ItemType SymbolicLink -Path "node_modules\locastrol" -Target "d:\test\locastrol"

把本地依赖软链接上,这样方便随改随测

软链接截图

奇异搞笑 astro: content 导入

我当时不明白,为什么我不能导入来获取这个方法,问了一下 Copilot:

import { getCollection } from "astro:content";

Copilot 回答说:astro:content 是 Astro 的虚拟模块,只在 Astro 项目运行时可用,于是它推荐了各种疯狂的高超技巧来实现获取内容合集,我照做了,但是总是感觉别扭。问另一个 AI,让我另辟蹊径,直接写 Astro 组件?

欸,果然只问一个 AI,这个 AI 就会犯轴,转不过弯,好多时间浪费在那了…

src/pages/admin.astro
---
import { getCollection } from "astro:content";
const POSTS = 'blog';
const posts = await getCollection(POSTS);
---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>hello world</div>
<ul><!-- 列出所有文章,具体类型先any,我喜欢anyscript :) -->
{posts.map((post: { slug: any; data: { title: unknown; }; }) => (
<li>
<a href={`/blog/${post.slug}`}>{post.data.title}</a>
</li>
))}
</ul>
</body>
</html>

直接通过组件来实现的内容集合查询

具体讲讲钩子这块

插件得先注入

这块主要是看官方的文档,首先我得配置一下我这个插件的注入方式,

src/index.ts
import { AstroIntegration } from 'astro';
interface Options{
collections: String;
}
export function IntergrationName(config: Options = { }): AstroIntegration {...}

这个应该是默认插件导出,导出名就是Intergration,然后在astro.config.mjs中配置一下

astro.config.mjs
import { defineConfig } from 'astro/config';
import { IntergrationName } from 'locastrol';
export default defineConfig({
integrations: [IntergrationName({...})],
});

钩子,对事件的响应,或者说回调?

很明显,钩子总是与事件有关 astro:config:setup这个钩子,在配置阶段触发,可以用来修改配置,比如说我想要在开发环境下,注入一些路由,或者是修改一些配置

我就注入了一些路由,比如说/locastrol/editor这个路由,它会指向src/pages/index.astro,也就是我的后台首页

💡

值得注意的是,以locastrol这个包名作为entrypoint的开头是因为我这个是npm包,得包名开头才能被识别为npm包的路径,不会导致astro混淆

而且还要确保包导出了这些文件

src/index.ts
hooks: {
'astro:config:setup': ({ injectRoute, updateConfig, command }) => {
if (command == 'dev') {
// 通过 Vite 环境变量传递 collections 参数
updateConfig({
vite: {
define: {
'import.meta.env.LOCASTROL_COLLECTIONS': JSON.stringify(collections)
}
}
});
// 后台首页
injectRoute({
pattern: '/locastrol/editor',
entrypoint: 'locastrol/src/pages/index.astro'
});
injectRoute({
pattern: '/locastrol/editor/[slug]',
entrypoint: 'locastrol/src/pages/[slug].astro'
});
}
},
}
⚠️

加上if (command == 'dev')条件判断很重要,不然ssg会把后台页面也渲染出来

到时候一些私密内存变量就会不小心暴露出来了

'astro:server:start': ({ address }) => {
console.log('\x1b[43m\x1b[30m%s\x1b[0m \x1b[36m%s\x1b[0m', '✅Locastrol后台已经启动', `http://localhost:${address.port}/locastrol/editor`);
},

这个钩子在服务器启动时触发,我在这里打印了一条日志,告诉用户后台已经启动,并给出访问地址,不过我好奇,为什么ai给我这么邪乎的颜色代码,就没有更好的实现吗?

roadmap ^ ^

看了一眼官方文档,暂时先俩这些钩子,先列个表单列出所有文章,后续查询可以使用官方的内容集合来做到,用nodejs api来做到增删改,也许可以再加个中间件来实现身份验证?

不过那倒是有点背离dev local后台的初心了,而且我还有好多功能没实现呢!

学习开发astro博客后台(一)钩子文学

作者: xingwangzhe

本文链接: https://xingwangzhe.fun/posts/f023e0e0

本文采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

留言评论

2000年1月1日星期六
00:00:00