Skip to content

Commit 195bb59

Browse files
Fix production SEO site URLs for website deployment (#5)
1 parent 0ee126c commit 195bb59

7 files changed

Lines changed: 70 additions & 33 deletions

File tree

‎.github/workflows/astro.yml‎

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ concurrency:
2626

2727
env:
2828
BUILD_PATH: "." # default value when not using subfolders
29+
PRODUCTION_SITE_URL: "https://1panel.cn"
2930
# BUILD_PATH: subfolder
3031

3132
jobs:
@@ -77,6 +78,18 @@ jobs:
7778
uses: actions/upload-pages-artifact@v3
7879
with:
7980
path: ${{ env.BUILD_PATH }}/dist
81+
- name: Build production artifact for 1panel.cn
82+
run: |
83+
rm -rf dist
84+
${{ steps.detect-package-manager.outputs.runner }} astro build \
85+
--site "${{ env.PRODUCTION_SITE_URL }}" \
86+
--base "./"
87+
working-directory: ${{ env.BUILD_PATH }}
88+
- name: Upload production artifact
89+
uses: actions/upload-artifact@v4
90+
with:
91+
name: production-site-dist
92+
path: ${{ env.BUILD_PATH }}/dist
8093

8194
deploy:
8295
environment:
@@ -105,17 +118,14 @@ jobs:
105118
- name: Download build artifact
106119
uses: actions/download-artifact@v4
107120
with:
108-
name: github-pages
121+
name: production-site-dist
109122
path: dist
110123

111124
- name: Copy build output to website-2026/1panel
112125
run: |
113126
rm -rf website-2026/1panel
114127
mkdir -p website-2026/1panel
115-
cd dist
116-
tar -xvf artifact.tar
117-
rm -rf artifact.tar
118-
cp -r ./* ../website-2026/1panel/
128+
cp -r dist/. website-2026/1panel/
119129
120130
- name: Configure Git
121131
run: |

‎src/layouts/Layout.astro‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ const {
3737
structuredData = [],
3838
} = Astro.props;
3939
40-
const siteUrl = Astro.site ?? new URL(SITE_URL);
40+
const siteUrl = (Astro.site ?? new URL(SITE_URL)).toString();
4141
const canonicalUrl = new URL(canonical ?? Astro.url.pathname, siteUrl).toString();
42-
const socialImageUrl = toAbsoluteUrl(image, siteUrl.toString());
42+
const socialImageUrl = toAbsoluteUrl(image, siteUrl);
4343
const keywordsContent = Array.isArray(keywords) ? keywords.join(",") : keywords;
4444
const robotsContent = noindex
4545
? "noindex, nofollow"
@@ -49,13 +49,14 @@ const extraStructuredData = Array.isArray(structuredData)
4949
? structuredData
5050
: [structuredData];
5151
const structuredDataItems = [
52-
createOrganizationSchema(),
52+
createOrganizationSchema(siteUrl),
5353
createWebPageSchema({
5454
title: schemaName,
5555
description,
5656
url: canonicalUrl,
57+
siteUrl,
5758
}),
58-
...(isHomePage ? [createWebsiteSchema()] : []),
59+
...(isHomePage ? [createWebsiteSchema(siteUrl)] : []),
5960
...extraStructuredData.filter(Boolean),
6061
];
6162
---

‎src/lib/seo.ts‎

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -24,35 +24,43 @@ export const DEFAULT_KEYWORDS = [
2424
];
2525
export const DEFAULT_OG_IMAGE = "/images/overview-full.png";
2626

27+
function normalizeSiteUrl(siteUrl: string = SITE_URL) {
28+
return new URL("/", siteUrl).toString().replace(/\/$/, "");
29+
}
30+
2731
export function toAbsoluteUrl(path: string, base: string = SITE_URL) {
28-
return new URL(path, base).toString();
32+
return new URL(path, normalizeSiteUrl(base)).toString();
2933
}
3034

31-
export function createOrganizationSchema(): StructuredData {
35+
export function createOrganizationSchema(siteUrl: string = SITE_URL): StructuredData {
36+
const resolvedSiteUrl = normalizeSiteUrl(siteUrl);
37+
3238
return {
3339
"@context": "https://schema.org",
3440
"@type": "Organization",
35-
"@id": `${SITE_URL}/#organization`,
41+
"@id": `${resolvedSiteUrl}/#organization`,
3642
name: ORGANIZATION_NAME,
3743
alternateName: ORGANIZATION_ALTERNATE_NAME,
3844
url: ORGANIZATION_URL,
39-
logo: toAbsoluteUrl("/images/logo-light-FIT2CLOUD.svg"),
45+
logo: toAbsoluteUrl("/images/logo-light-FIT2CLOUD.svg", resolvedSiteUrl),
4046
sameAs: [ORGANIZATION_URL],
4147
};
4248
}
4349

44-
export function createWebsiteSchema(): StructuredData {
50+
export function createWebsiteSchema(siteUrl: string = SITE_URL): StructuredData {
51+
const resolvedSiteUrl = normalizeSiteUrl(siteUrl);
52+
4553
return {
4654
"@context": "https://schema.org",
4755
"@type": "WebSite",
48-
"@id": `${SITE_URL}/#website`,
56+
"@id": `${resolvedSiteUrl}/#website`,
4957
name: `${SITE_NAME} 官网`,
5058
alternateName: SITE_NAME,
51-
url: `${SITE_URL}/`,
59+
url: `${resolvedSiteUrl}/`,
5260
inLanguage: "zh-CN",
5361
description: DEFAULT_DESCRIPTION,
5462
publisher: {
55-
"@id": `${SITE_URL}/#organization`,
63+
"@id": `${resolvedSiteUrl}/#organization`,
5664
},
5765
};
5866
}
@@ -61,11 +69,15 @@ export function createWebPageSchema({
6169
title,
6270
description,
6371
url,
72+
siteUrl = SITE_URL,
6473
}: {
6574
title: string;
6675
description: string;
6776
url: string;
77+
siteUrl?: string;
6878
}): StructuredData {
79+
const resolvedSiteUrl = normalizeSiteUrl(siteUrl);
80+
6981
return {
7082
"@context": "https://schema.org",
7183
"@type": "WebPage",
@@ -75,40 +87,42 @@ export function createWebPageSchema({
7587
description,
7688
inLanguage: "zh-CN",
7789
isPartOf: {
78-
"@id": `${SITE_URL}/#website`,
90+
"@id": `${resolvedSiteUrl}/#website`,
7991
},
8092
about: {
8193
"@type": "Thing",
8294
name: SITE_NAME,
8395
},
8496
publisher: {
85-
"@id": `${SITE_URL}/#organization`,
97+
"@id": `${resolvedSiteUrl}/#organization`,
8698
},
8799
};
88100
}
89101

90-
export function createSoftwareApplicationSchema(): StructuredData {
102+
export function createSoftwareApplicationSchema(siteUrl: string = SITE_URL): StructuredData {
103+
const resolvedSiteUrl = normalizeSiteUrl(siteUrl);
104+
91105
return {
92106
"@context": "https://schema.org",
93107
"@type": "SoftwareApplication",
94-
"@id": `${SITE_URL}/#software`,
108+
"@id": `${resolvedSiteUrl}/#software`,
95109
name: SITE_NAME,
96-
url: `${SITE_URL}/`,
110+
url: `${resolvedSiteUrl}/`,
97111
description: DEFAULT_DESCRIPTION,
98112
applicationCategory: "DeveloperApplication",
99113
operatingSystem: "Linux",
100-
image: toAbsoluteUrl(DEFAULT_OG_IMAGE),
101-
screenshot: toAbsoluteUrl("/images/dashboard-preview.png"),
114+
image: toAbsoluteUrl(DEFAULT_OG_IMAGE, resolvedSiteUrl),
115+
screenshot: toAbsoluteUrl("/images/dashboard-preview.png", resolvedSiteUrl),
102116
downloadUrl: GITHUB_URL,
103-
softwareHelp: toAbsoluteUrl("/docs"),
117+
softwareHelp: toAbsoluteUrl("/docs", resolvedSiteUrl),
104118
isAccessibleForFree: true,
105119
offers: {
106120
"@type": "Offer",
107121
price: "0",
108122
priceCurrency: "CNY",
109123
},
110124
publisher: {
111-
"@id": `${SITE_URL}/#organization`,
125+
"@id": `${resolvedSiteUrl}/#organization`,
112126
},
113127
sameAs: [GITHUB_URL],
114128
featureList: [

‎src/pages/about.astro‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import LanguageModal from "../components/LanguageModal.astro";
77
import {
88
SITE_URL,
99
createBreadcrumbSchema,
10+
toAbsoluteUrl,
1011
} from "../lib/seo";
1112
import "../styles/global.css";
13+
14+
const siteUrl = Astro.site?.toString() ?? SITE_URL;
1215
---
1316

1417
<Layout
@@ -27,8 +30,8 @@ import "../styles/global.css";
2730
]}
2831
structuredData={[
2932
createBreadcrumbSchema([
30-
{ name: "1Panel 官网", url: `${SITE_URL}/` },
31-
{ name: "关于 1Panel", url: `${SITE_URL}/about.html` },
33+
{ name: "1Panel 官网", url: toAbsoluteUrl("/", siteUrl) },
34+
{ name: "关于 1Panel", url: toAbsoluteUrl("/about.html", siteUrl) },
3235
]),
3336
]}
3437
>

‎src/pages/index.astro‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@ import CTA from '../components/CTA.astro';
1212
import Footer from '../components/Footer.astro';
1313
import LanguageModal from '../components/LanguageModal.astro';
1414
import {
15+
SITE_URL,
1516
createSoftwareApplicationSchema,
1617
} from '../lib/seo';
1718
import '../styles/global.css';
19+
20+
const siteUrl = Astro.site?.toString() ?? SITE_URL;
1821
---
1922

2023
<Layout
@@ -35,7 +38,7 @@ import '../styles/global.css';
3538
"数据库管理",
3639
"AI 模型管理",
3740
]}
38-
structuredData={[createSoftwareApplicationSchema()]}
41+
structuredData={[createSoftwareApplicationSchema(siteUrl)]}
3942
>
4043
<Statistics slot="head" />
4144
<Fragment slot="main">

‎src/pages/openclaw.astro‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import { Icon } from 'astro-icon/components'
77
import {
88
SITE_URL,
99
createBreadcrumbSchema,
10+
toAbsoluteUrl,
1011
} from "../lib/seo";
1112
import "../styles/global.css";
13+
14+
const siteUrl = Astro.site?.toString() ?? SITE_URL;
1215
---
1316

1417
<Layout
@@ -27,8 +30,8 @@ import "../styles/global.css";
2730
]}
2831
structuredData={[
2932
createBreadcrumbSchema([
30-
{ name: "1Panel 官网", url: `${SITE_URL}/` },
31-
{ name: "OpenClaw 一体机", url: `${SITE_URL}/openclaw.html` },
33+
{ name: "1Panel 官网", url: toAbsoluteUrl("/", siteUrl) },
34+
{ name: "OpenClaw 一体机", url: toAbsoluteUrl("/openclaw.html", siteUrl) },
3235
]),
3336
]}
3437
>

‎src/pages/self-hosted.astro‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import LanguageModal from "../components/LanguageModal.astro";
77
import {
88
SITE_URL,
99
createBreadcrumbSchema,
10+
toAbsoluteUrl,
1011
} from "../lib/seo";
1112
import "../styles/global.css";
13+
14+
const siteUrl = Astro.site?.toString() ?? SITE_URL;
1215
---
1316

1417
<Layout
@@ -25,8 +28,8 @@ import "../styles/global.css";
2528
]}
2629
structuredData={[
2730
createBreadcrumbSchema([
28-
{ name: "1Panel 官网", url: `${SITE_URL}/` },
29-
{ name: "1Panel 自托管解决方案", url: `${SITE_URL}/self-hosted.html` },
31+
{ name: "1Panel 官网", url: toAbsoluteUrl("/", siteUrl) },
32+
{ name: "1Panel 自托管解决方案", url: toAbsoluteUrl("/self-hosted.html", siteUrl) },
3033
]),
3134
]}
3235
>

0 commit comments

Comments
 (0)