Skip to content

Commit 139cffd

Browse files
authored
feat: refactor site configuration handling (#430)
* chore: update build and deployment scripts for improved client build handling * feat: Refactor site configuration handling - Update site configuration to be fetched dynamically from the server at runtime, removing the need for frontend environment variables during build. - Introduce new hooks (`useSiteConfig` and `useSiteConfigValue`) to access site configuration values throughout the client. - Modify various components and pages to utilize the new site configuration methods for displaying site name, description, avatar, and pagination size. - Update documentation to reflect changes in environment variable usage and site configuration management. - Remove legacy environment variable handling in the client build process.
1 parent 1949947 commit 139cffd

32 files changed

Lines changed: 310 additions & 137 deletions

.env.example

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,25 @@
22
# 复制此文件为 .env.local 并填入你的实际配置
33

44
# ============================================
5-
# 前端配置 (client/.env)
5+
# 站点配置(可选,默认值如下)
6+
# 注意:这些配置可以在部署后通过设置页面修改
7+
# 配置优先级:设置页面 > 环境变量 > 默认值
68
# ============================================
7-
FRONTEND_PORT=5173
89

9-
# 网站基本信息
10-
NAME=YourName
11-
DESCRIPTION=Your Description
12-
AVATAR=https://avatars.githubusercontent.com/u/your-id
10+
# 网站基本信息(默认:Rin)
11+
# NAME=Rin
1312

14-
# 分页设置
15-
PAGE_SIZE=5
13+
# 网站描述(默认:A lightweight personal blogging system)
14+
# DESCRIPTION=A lightweight personal blogging system
1615

17-
# RSS 设置
18-
RSS_ENABLE=false
16+
# 头像地址(默认:空)
17+
# AVATAR=
18+
19+
# 分页大小(默认:5)
20+
# PAGE_SIZE=5
21+
22+
# RSS 设置(默认:false)
23+
# RSS_ENABLE=false
1924

2025
# ============================================
2126
# 后端配置 (wrangler.toml 中的 vars)

.github/workflows/build.yml

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,13 @@ jobs:
4848
echo "${{ github.sha }}" > ./build-meta/sha
4949
echo "${{ github.event.pull_request.head.sha || github.sha }}" > ./build-meta/head_sha
5050
51-
# Build client with production environment variables (must be before server build)
52-
- name: Build client for production
53-
env:
54-
NAME: ${{ vars.NAME || 'Rin' }}
55-
DESCRIPTION: ${{ vars.DESCRIPTION || 'A lightweight personal blogging system' }}
56-
AVATAR: ${{ vars.AVATAR || '' }}
57-
PAGE_SIZE: ${{ vars.PAGE_SIZE || '5' }}
58-
RSS_ENABLE: ${{ vars.RSS_ENABLE || 'false' }}
51+
# Build client (no env vars needed, config is fetched from server at runtime)
52+
# Note: vite.config.ts builds directly to ../dist/client
53+
- name: Build client
5954
run: |
60-
mkdir -p ./dist/client
6155
cd client
62-
echo "NAME=${NAME}" > .env.production
63-
echo "DESCRIPTION=${DESCRIPTION}" >> .env.production
64-
echo "AVATAR=${AVATAR}" >> .env.production
65-
echo "PAGE_SIZE=${PAGE_SIZE}" >> .env.production
66-
echo "RSS_ENABLE=${RSS_ENABLE}" >> .env.production
6756
bun run build
6857
cd ..
69-
cp -r ./client/dist/* ./dist/client/
7058
7159
# Generate wrangler.toml for build (required by wrangler deploy --dry-run)
7260
- name: Setup Wrangler

.github/workflows/release.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,12 @@ jobs:
7878
with:
7979
mode: 'dry-run'
8080

81+
# Note: vite.config.ts builds directly to ../dist/client
8182
- name: Build client
8283
run: |
83-
mkdir -p ./dist/client
8484
cd client
8585
bun run build
8686
cd ..
87-
cp -r ./client/dist/* ./dist/client/
8887
8988
- name: Build server
9089
run: |

.github/workflows/test.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ name: CI - Test and Type Check
22

33
on:
44
push:
5-
branches: [main, develop]
5+
branches: [main, trunk]
66
pull_request:
7-
branches: [main, develop]
7+
branches: [main, trunk]
88

99
jobs:
1010
test-server:

client/public/locales/en/translation.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,29 @@
255255
"other": {
256256
"title": "Other Settings"
257257
},
258+
"site": {
259+
"title": "Site Information",
260+
"name": {
261+
"title": "Site Name",
262+
"desc": "Set the website name displayed in the site title and navigation bar",
263+
"label": "Site Name"
264+
},
265+
"description": {
266+
"title": "Site Description",
267+
"desc": "Set the short description displayed in the navigation bar",
268+
"label": "Site Description"
269+
},
270+
"avatar": {
271+
"title": "Site Avatar",
272+
"desc": "Set the avatar URL displayed in the navigation bar",
273+
"label": "Avatar URL"
274+
},
275+
"page_size": {
276+
"title": "Page Size",
277+
"desc": "Set the number of articles displayed per page in the list",
278+
"label": "Articles per page"
279+
}
280+
},
258281
"rss": {
259282
"desc": "Enable RSS subscription link at the site footer",
260283
"title": "RSS Subscription Link"

client/public/locales/zh-CN/translation.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,29 @@
255255
"other": {
256256
"title": "其他设置"
257257
},
258+
"site": {
259+
"title": "站点信息",
260+
"name": {
261+
"title": "站点名称",
262+
"desc": "设置显示在站点标题和导航栏的网站名称",
263+
"label": "站点名称"
264+
},
265+
"description": {
266+
"title": "站点描述",
267+
"desc": "设置显示在导航栏的简短描述",
268+
"label": "站点描述"
269+
},
270+
"avatar": {
271+
"title": "站点头像",
272+
"desc": "设置显示在导航栏的头像 URL",
273+
"label": "头像 URL"
274+
},
275+
"page_size": {
276+
"title": "分页大小",
277+
"desc": "设置文章列表每页显示的数量",
278+
"label": "每页文章数"
279+
}
280+
},
258281
"rss": {
259282
"desc": "启用站点底部 RSS 订阅链接",
260283
"title": "RSS 订阅链接"

client/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function App() {
7373
}
7474
ref.current = true
7575
}, [])
76-
const favicon = `${process.env.API_URL}/favicon`;
76+
const favicon = '/favicon';
7777
return (
7878
<>
7979
<ClientConfigContext.Provider value={config}>

client/src/components/error-boundary.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,11 +112,10 @@ export class GlobalErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoun
112112
// Call custom error handler if provided
113113
this.props.onError?.(error, errorInfo);
114114

115-
// Send to error tracking service in production
116-
if (process.env.NODE_ENV === 'production') {
117-
// TODO: Integrate with error tracking service (e.g., Sentry)
118-
// reportError(error, errorInfo);
119-
}
115+
// TODO: Integrate with error tracking service (e.g., Sentry)
116+
// if (import.meta.env.PROD) {
117+
// reportError(error, errorInfo);
118+
// }
120119
}
121120

122121
componentDidUpdate(prevProps: ErrorBoundaryProps) {

client/src/components/header.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import { Padding } from "./padding";
1111
import { ClientConfigContext } from "../state/config";
1212
import { client } from "../main";
1313
import { removeAuthToken } from "../utils/auth";
14+
import { useSiteConfig } from "../hooks/useSiteConfig";
1415

1516

1617
export function Header({ children }: { children?: React.ReactNode }) {
1718
const profile = useContext(ProfileContext);
1819
const { t } = useTranslation()
20+
const siteConfig = useSiteConfig();
1921

2022
return useMemo(() => (
2123
<>
@@ -25,13 +27,13 @@ export function Header({ children }: { children?: React.ReactNode }) {
2527
<div className="w-full flex justify-between items-center">
2628
<Link aria-label={t('home')} href="/"
2729
className="hidden opacity-0 md:opacity-100 duration-300 mr-auto md:flex flex-row items-center">
28-
<img src={process.env.AVATAR} alt="Avatar" className="w-12 h-12 rounded-2xl border-2" />
30+
<img src={siteConfig.avatar} alt="Avatar" className="w-12 h-12 rounded-2xl border-2" />
2931
<div className="flex flex-col justify-center items-start mx-4">
3032
<p className="text-xl font-bold dark:text-white">
31-
{process.env.NAME}
33+
{siteConfig.name}
3234
</p>
3335
<p className="text-xs text-neutral-500">
34-
{process.env.DESCRIPTION}
36+
{siteConfig.description}
3537
</p>
3638
</div>
3739
</Link>
@@ -41,14 +43,14 @@ export function Header({ children }: { children?: React.ReactNode }) {
4143
className="flex flex-row items-center bg-w t-primary rounded-full px-2 shadow-xl shadow-light">
4244
<Link aria-label={t('home')} href="/"
4345
className="visible opacity-100 md:hidden md:opacity-0 duration-300 mr-auto flex flex-row items-center py-2">
44-
<img src={process.env.AVATAR} alt="Avatar"
46+
<img src={siteConfig.avatar} alt="Avatar"
4547
className="w-10 h-10 rounded-full border-2" />
4648
<div className="flex flex-col justify-center items-start mx-2">
4749
<p className="text-sm font-bold">
48-
{process.env.NAME}
50+
{siteConfig.name}
4951
</p>
5052
<p className="text-xs text-neutral-500">
51-
{process.env.DESCRIPTION}
53+
{siteConfig.description}
5254
</p>
5355
</div>
5456
</Link>
@@ -68,7 +70,7 @@ export function Header({ children }: { children?: React.ReactNode }) {
6870
</div>
6971
<div className="h-20"></div>
7072
</>
71-
), [profile, children])
73+
), [profile, children, siteConfig])
7274
}
7375

7476
function NavItem({ menu, title, selected, href, when = true, onClick }: {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Helmet } from "react-helmet";
2+
import { useSiteConfig } from "../hooks/useSiteConfig";
3+
4+
interface SiteMetaProps {
5+
title?: string;
6+
description?: string;
7+
image?: string;
8+
children: React.ReactNode;
9+
}
10+
11+
// Component to provide site metadata for pages
12+
export function SiteMeta({ title, description, image, children }: SiteMetaProps) {
13+
const siteConfig = useSiteConfig();
14+
15+
const pageTitle = title
16+
? `${title} - ${siteConfig.name}`
17+
: siteConfig.name;
18+
19+
const pageDescription = description || siteConfig.description;
20+
const pageImage = image || siteConfig.avatar;
21+
22+
return (
23+
<>
24+
<Helmet>
25+
<title>{pageTitle}</title>
26+
<meta property="og:title" content={pageTitle} />
27+
<meta property="og:description" content={pageDescription} />
28+
{pageImage && <meta property="og:image" content={pageImage} />}
29+
</Helmet>
30+
{children}
31+
</>
32+
);
33+
}

0 commit comments

Comments
 (0)