优化结构

This commit is contained in:
2026-06-18 21:44:37 +08:00 Unverified
parent 3051fe2d6a
commit cb244eb983
74 changed files with 94 additions and 144 deletions
+10 -13
View File
@@ -1,4 +1,4 @@
name: 自动部署
name: 鑷姩閮ㄧ讲
on:
push:
branches:
@@ -13,11 +13,11 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: 检查分支
- name: 妫€鏌ュ垎鏀?
uses: actions/checkout@v4
with:
ref: master
- name: 缓存项目 npm
- name: 缂撳瓨椤圭洰 npm 鍖?
id: cache-node-modules
uses: actions/cache@v3
with:
@@ -25,31 +25,28 @@ jobs:
key: ${{ runner.os }}-nodeModules-${{ hashFiles('package-lock.json') }}-${{ hashFiles('package.json') }}
restore-keys: |
${{ runner.os }}-nodeModules-
- name: 安装 Node
- name: 瀹夎 Node
uses: actions/setup-node@v4
with:
node-version: "22.x"
- name: 安装 Hexo
run: |
npm install hexo-cli --global
- name: 安装依赖
- name: 瀹夎渚濊禆
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: |
npm install
- name: 清理文件树
- name: 娓呯悊鏂囦欢鏍?
run: |
npm run clean
- name: 生成静态文件并压缩
- name: 鐢熸垚闈欐€佹枃浠跺苟鍘嬬缉
run: |
npm run build
- name: 部署
- name: 閮ㄧ讲
run: |
cd ./public
cd ./dist
git init
git config user.name "${{ gitea.actor }}"
git config user.email "${{ gitea.actor }}@noreply.gitea.io"
git add .
git commit -m "${{ gitea.event.head_commit.message }}··[$(date +"%Z %Y-%m-%d %A %H:%M:%S")]"
git commit -m "${{ gitea.event.head_commit.message }}路路[$(date +"%Z %Y-%m-%d %A %H:%M:%S")]"
git push --force --quiet "https://${{ gitea.actor }}:${{ secrets.DEPLOY_TOKEN }}@git.biss.click/biss/blog.git" master:page
- name: Deploy to Server
run: |
+1 -1
View File
@@ -4,7 +4,7 @@ db.json
*.log
node_modules/
.astro/
public/
dist/
.deploy*/
_multiconfig.yml
.hintrc
-2
View File
@@ -8,8 +8,6 @@ import remarkHexoLinkCards from './src/lib/remarkHexoLinkCards.mjs';
export default defineConfig({
site: 'https://blog.biss.click',
output: 'static',
outDir: './public',
publicDir: './static',
integrations: [sitemap()],
markdown: {
processor: unified({

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Before

Width:  |  Height:  |  Size: 457 KiB

After

Width:  |  Height:  |  Size: 457 KiB

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Before

Width:  |  Height:  |  Size: 269 KiB

After

Width:  |  Height:  |  Size: 269 KiB

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 64 KiB

+1 -1
View File
@@ -1,7 +1,7 @@
import { readdir, readFile, writeFile } from 'node:fs/promises';
import { basename, extname, join, relative } from 'node:path';
const POSTS_DIR = join(process.cwd(), 'posts');
const POSTS_DIR = join(process.cwd(), 'src', 'content', 'posts');
const CRC32_TABLE = new Uint32Array(256);
+19
View File
@@ -0,0 +1,19 @@
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const posts = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
schema: z.object({
title: z.any().optional(),
date: z.any().optional(),
abbrlink: z.any().optional(),
tags: z.any().optional(),
categories: z.any().optional(),
summary: z.any().optional(),
description: z.any().optional(),
comments: z.any().optional(),
cover: z.any().optional(),
}).passthrough(),
});
export const collections = { posts };
-37
View File
@@ -1,37 +0,0 @@
type PageModule = {
frontmatter: Record<string, unknown>;
Content: unknown;
rawContent?: () => string;
};
export type SitePage = PageModule & {
title: string;
slug: string;
};
const modules = import.meta.glob<PageModule>('/source/**/index.md', { eager: true });
export function getSitePages(): SitePage[] {
return Object.entries(modules)
.filter(([path]) => {
if (path.includes('/_posts/') || path.includes('/_drafts/')) return false;
return ![
'/source/about/index.md',
'/source/cc/index.md',
'/source/cookie/index.md',
'/source/link/index.md',
'/source/privacy/index.md',
'/source/categories/index.md',
'/source/tags/index.md',
'/source/shuoshuo/index.md',
].includes(path);
})
.map(([path, module]) => {
const slug = path.replace('/source/', '').replace('/index.md', '');
return {
...module,
title: String(module.frontmatter.title ?? slug),
slug,
};
});
}
+29 -31
View File
@@ -1,11 +1,8 @@
type MarkdownModule = {
frontmatter: Record<string, unknown>;
Content: unknown;
rawContent?: () => string;
file?: string;
};
import type { CollectionEntry } from 'astro:content';
import { getCollection } from 'astro:content';
export type BlogPost = MarkdownModule & {
export type BlogPost = {
entry: CollectionEntry<'posts'>;
title: string;
slug: string;
date: Date;
@@ -16,10 +13,9 @@ export type BlogPost = MarkdownModule & {
comments: boolean;
cover?: string;
href: string;
body: string;
};
const modules = import.meta.glob<MarkdownModule>('/posts/**/*.md', { eager: true });
function asArray(value: unknown): string[] {
if (Array.isArray(value)) return value.map(String).filter(Boolean);
if (typeof value === 'string' && value.trim()) return [value.trim()];
@@ -43,20 +39,19 @@ function formatDate(date: Date): string {
}).format(date);
}
function fallbackSlug(path: string): string {
return path
function fallbackSlug(id: string): string {
return id
.split('/')
.pop()
?.replace(/\.md$/, '')
.toLowerCase() ?? 'post';
}
function makeSummary(module: MarkdownModule): string {
const explicit = module.frontmatter.summary ?? module.frontmatter.description;
function makeSummary(entry: CollectionEntry<'posts'>): string {
const explicit = entry.data.summary ?? entry.data.description;
if (typeof explicit === 'string' && explicit.trim()) return explicit.trim();
const raw = module.rawContent?.() ?? '';
return raw
return entry.body
.replace(/```[\s\S]*?```/g, '')
.replace(/<[^>]+>/g, '')
.replace(/[#>*_`~\-\[\]\(\)]/g, '')
@@ -65,34 +60,37 @@ function makeSummary(module: MarkdownModule): string {
.slice(0, 120);
}
export function getAllPosts(): BlogPost[] {
return Object.entries(modules)
.map(([path, module]) => {
const date = toDate(module.frontmatter.date);
const slug = String(module.frontmatter.abbrlink ?? fallbackSlug(path));
const title = String(module.frontmatter.title ?? slug);
export async function getAllPosts(): Promise<BlogPost[]> {
const entries = await getCollection('posts');
return entries
.map((entry) => {
const date = toDate(entry.data.date);
const slug = String(entry.data.abbrlink ?? fallbackSlug(entry.id));
const title = String(entry.data.title ?? slug);
return {
...module,
entry,
title,
slug,
date,
dateText: formatDate(date),
tags: asArray(module.frontmatter.tags),
categories: asArray(module.frontmatter.categories),
summary: makeSummary(module),
comments: module.frontmatter.comments !== false,
cover: typeof module.frontmatter.cover === 'string' ? module.frontmatter.cover : undefined,
tags: asArray(entry.data.tags),
categories: asArray(entry.data.categories),
summary: makeSummary(entry),
comments: entry.data.comments !== false,
cover: typeof entry.data.cover === 'string' ? entry.data.cover : undefined,
href: `/posts/${slug}/`,
body: entry.body,
};
})
.sort((a, b) => b.date.valueOf() - a.date.valueOf());
}
export function getAllTags(): string[] {
return [...new Set(getAllPosts().flatMap((post) => post.tags))].sort((a, b) => a.localeCompare(b, 'zh-CN'));
export async function getAllTags(): Promise<string[]> {
return [...new Set((await getAllPosts()).flatMap((post) => post.tags))].sort((a, b) => a.localeCompare(b, 'zh-CN'));
}
export function getAllCategories(): string[] {
return [...new Set(getAllPosts().flatMap((post) => post.categories))].sort((a, b) => a.localeCompare(b, 'zh-CN'));
export async function getAllCategories(): Promise<string[]> {
return [...new Set((await getAllPosts()).flatMap((post) => post.categories))].sort((a, b) => a.localeCompare(b, 'zh-CN'));
}
-26
View File
@@ -1,26 +0,0 @@
---
import BaseLayout from '@/layouts/BaseLayout.astro';
import PageHeaderCard from '@/components/PageHeaderCard.astro';
import { getSitePages } from '@/lib/pages';
export function getStaticPaths() {
return getSitePages().map((page) => ({
params: { slug: page.slug },
props: { page },
}));
}
const { page } = Astro.props;
const { Content } = page;
---
<BaseLayout title={page.title}>
<section class="content-wrap narrow page-with-card">
<PageHeaderCard title={page.title} />
</section>
<article class="article page-article">
<div class="prose">
<Content />
</div>
</article>
</BaseLayout>
+2 -2
View File
@@ -1,7 +1,7 @@
import { getAllPosts } from '@/lib/posts';
export function GET() {
const posts = getAllPosts().map((post) => ({
export async function GET() {
const posts = (await getAllPosts()).map((post) => ({
title: post.title,
href: post.href,
}));
+1 -1
View File
@@ -5,7 +5,7 @@ import PageHeaderCard from '@/components/PageHeaderCard.astro';
import { getAllPosts } from '@/lib/posts';
import { getPageSlice } from '@/lib/pagination';
const posts = getAllPosts();
const posts = await getAllPosts();
const pageData = getPageSlice(posts, 1);
---
+3 -3
View File
@@ -5,8 +5,8 @@ import PageHeaderCard from '@/components/PageHeaderCard.astro';
import { getAllPosts } from '@/lib/posts';
import { getPageSlice, getPaginationPaths } from '@/lib/pagination';
export function getStaticPaths() {
const posts = getAllPosts();
export async function getStaticPaths() {
const posts = await getAllPosts();
return getPaginationPaths(posts).map((page) => ({
params: { page: String(page) },
@@ -15,7 +15,7 @@ export function getStaticPaths() {
}
const { page } = Astro.props;
const posts = getAllPosts();
const posts = await getAllPosts();
const pageData = getPageSlice(posts, page);
---
+3 -3
View File
@@ -4,15 +4,15 @@ import PageHeaderCard from '@/components/PageHeaderCard.astro';
import PostCard from '@/components/PostCard.astro';
import { getAllCategories, getAllPosts } from '@/lib/posts';
export function getStaticPaths() {
return getAllCategories().map((category) => ({
export async function getStaticPaths() {
return (await getAllCategories()).map((category) => ({
params: { category },
props: { category },
}));
}
const { category } = Astro.props;
const posts = getAllPosts().filter((post) => post.categories.includes(category));
const posts = (await getAllPosts()).filter((post) => post.categories.includes(category));
---
<BaseLayout title={category}>
+2 -2
View File
@@ -3,8 +3,8 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
import PageHeaderCard from '@/components/PageHeaderCard.astro';
import { getAllCategories, getAllPosts } from '@/lib/posts';
const posts = getAllPosts();
const categories = getAllCategories();
const posts = await getAllPosts();
const categories = await getAllCategories();
---
<BaseLayout title="分类">
+3 -3
View File
@@ -6,9 +6,9 @@ import PostCard from '@/components/PostCard.astro';
import { getAllCategories, getAllPosts, getAllTags } from '@/lib/posts';
import { getPageSlice } from '@/lib/pagination';
const posts = getAllPosts();
const tags = getAllTags();
const categories = getAllCategories();
const posts = await getAllPosts();
const tags = await getAllTags();
const categories = await getAllCategories();
const pageData = getPageSlice(posts, 1);
---
+5 -5
View File
@@ -6,8 +6,8 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
import { getAllCategories, getAllPosts, getAllTags } from '@/lib/posts';
import { getPageSlice, getPaginationPaths } from '@/lib/pagination';
export function getStaticPaths() {
const posts = getAllPosts();
export async function getStaticPaths() {
const posts = await getAllPosts();
return getPaginationPaths(posts).map((page) => ({
params: { page: String(page) },
@@ -16,9 +16,9 @@ export function getStaticPaths() {
}
const { page } = Astro.props;
const posts = getAllPosts();
const tags = getAllTags();
const categories = getAllCategories();
const posts = await getAllPosts();
const tags = await getAllTags();
const categories = await getAllCategories();
const pageData = getPageSlice(posts, page);
---
+7 -6
View File
@@ -3,19 +3,20 @@ import ArticleSidebar from '@/components/ArticleSidebar.astro';
import PostCopyrightCard from '@/components/PostCopyrightCard.astro';
import TwikooComments from '@/components/TwikooComments.astro';
import BaseLayout from '@/layouts/BaseLayout.astro';
import { render } from 'astro:content';
import { getAllPosts } from '@/lib/posts';
export function getStaticPaths() {
return getAllPosts().map((post) => ({
export async function getStaticPaths() {
return (await getAllPosts()).map((post) => ({
params: { slug: post.slug },
props: { post },
}));
}
const { post } = Astro.props;
const { Content } = post;
const allPosts = getAllPosts();
const rawContent = post.rawContent?.() ?? '';
const { Content } = await render(post.entry);
const allPosts = await getAllPosts();
const rawContent = post.body;
const textContent = rawContent
.replace(/```[\s\S]*?```/g, '')
.replace(/<[^>]+>/g, '')
@@ -69,7 +70,7 @@ function makeToc(raw: string) {
});
}
const toc = makeToc(post.rawContent?.() ?? '');
const toc = makeToc(post.body);
const relatedPosts = allPosts
.filter((item) => item.slug !== post.slug)
.filter((item) => item.categories.some((category) => post.categories.includes(category)))
+2 -2
View File
@@ -1,8 +1,8 @@
import rss from '@astrojs/rss';
import { getAllPosts } from '@/lib/posts';
export function GET(context) {
const posts = getAllPosts();
export async function GET(context) {
const posts = await getAllPosts();
return rss({
title: "Bi's Blog",
+3 -3
View File
@@ -4,15 +4,15 @@ import PageHeaderCard from '@/components/PageHeaderCard.astro';
import PostCard from '@/components/PostCard.astro';
import { getAllPosts, getAllTags } from '@/lib/posts';
export function getStaticPaths() {
return getAllTags().map((tag) => ({
export async function getStaticPaths() {
return (await getAllTags()).map((tag) => ({
params: { tag },
props: { tag },
}));
}
const { tag } = Astro.props;
const posts = getAllPosts().filter((post) => post.tags.includes(tag));
const posts = (await getAllPosts()).filter((post) => post.tags.includes(tag));
---
<BaseLayout title={tag}>
+2 -2
View File
@@ -3,8 +3,8 @@ import BaseLayout from '@/layouts/BaseLayout.astro';
import PageHeaderCard from '@/components/PageHeaderCard.astro';
import { getAllPosts, getAllTags } from '@/lib/posts';
const posts = getAllPosts();
const tags = getAllTags();
const posts = await getAllPosts();
const tags = await getAllTags();
---
<BaseLayout title="标签">