build: 升级工程依赖与工具链并完善部署工作流

This commit is contained in:
seahi committed 2026-08-07 12:53:42 +08:00
1 parent e1948a7b4b
commit 457329d6c0
14 files changed
+3295 -1605

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
# BlogFlare Project Rules # BlogFlare Project Rules
## Package Manager ## Package Manager
- **ALWAYS use `pnpm`** as the package manager for this project. Do not use `npm` or `yarn`. - **ALWAYS use `pnpm`** as the package manager for this project. Do not use `npm` or `yarn`.
- When running one-off scripts, use `pnpm dlx` instead of `npx`. - When running one-off scripts, use `pnpm dlx` instead of `npx`.
- When installing dependencies, use `pnpm install` or `pnpm add`. - When installing dependencies, use `pnpm install` or `pnpm add`.
+3
View File
@@ -0,0 +1,3 @@
# Required when exercising production-mode admin routes locally.
CF_ACCESS_TEAM_DOMAIN=https://your-team.cloudflareaccess.com
CF_ACCESS_AUD=your-access-application-audience
+28 -14
View File
@@ -19,33 +19,47 @@ jobs:
with: with:
fetch-depth: 1 fetch-depth: 1
# 2. 初始化 Node.js 运行环境 (使用 Node 22) # 2. 使用与 packageManager 字段一致的 pnpm
- name: 2. 初始化 Node.js 环境 - name: 2. 初始化 pnpm 环境
uses: pnpm/action-setup@v4
with:
version: 11.20.0
# 3. 初始化 Node.js 运行环境 (使用 Node 22)
- name: 3. 初始化 Node.js 环境
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '22' node-version: '22'
cache: 'pnpm'
# 3. 全局安装 pnpm 11
- name: 3. 全局安装 pnpm (对应当前开发环境的 11.x 体系)
run: npm install -g pnpm@11
# 4. 安装工程依赖包 # 4. 安装工程依赖包
- name: 4. 安装工程依赖包 - name: 4. 安装工程依赖包
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
# 5. 执行类型自检并打包输出静态产物 (产出在 .svelte-kit/cloudflare) # 5. 执行静态代码整洁规则审查及 Svelte/TS 类型质检关卡
- name: 5. 构建生产环境打包产物 - name: 5. 执行代码规范、类型与自动化测试质检
run: pnpm run check && pnpm run lint && pnpm run test
# 6. 执行类型自检并打包输出静态产物 (产出在 .svelte-kit/cloudflare)
- name: 6. 构建生产环境打包产物
run: pnpm run build run: pnpm run build
# 6. 使用本地安装好的 wrangler 直接推送部署 # 7. 应用 D1 数据库增量迁移至远端生产区
- name: 6. 自动化推送到 Cloudflare Pages (主分支为生产发布) - name: 7. 应用数据库增量迁移至云端 (D1 Migrations)
env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: pnpm exec wrangler d1 migrations apply blogflare-db --remote
# 8. 使用本地安装好的 wrangler 直接推送部署
- name: 8. 自动化推送到 Cloudflare Pages (主分支为生产发布)
env: env:
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
run: pnpm exec wrangler pages deploy .svelte-kit/cloudflare --project-name=blogflare --branch=main run: pnpm exec wrangler pages deploy .svelte-kit/cloudflare --project-name=blogflare --branch=main
# 7. 构建与发布成功时,用 curl 直联调用 Telegram 官方发送通知接口 # 9. 构建与发布成功时,用 curl 直联调用 Telegram 官方发送通知接口
- name: 7. 发送 Telegram 部署成功通知 - name: 9. 发送 Telegram 部署成功通知
if: success() if: success()
env: env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
@@ -58,8 +72,8 @@ jobs:
-d "parse_mode=HTML" \ -d "parse_mode=HTML" \
--data-urlencode "text=${MSG}" --data-urlencode "text=${MSG}"
# 8. 一旦任意步骤发生阻挠或错误,立即发警报知音 # 10. 一旦任意步骤发生阻挠或错误,立即发警报知音
- name: 8. 发送 Telegram 部署失败告警 - name: 10. 发送 Telegram 部署失败告警
if: failure() if: failure()
env: env:
TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
+2
View File
@@ -38,6 +38,8 @@ lerna-debug.log*
.env.* .env.*
!.env.example !.env.example
!.env.test !.env.test
.dev.vars*
!.dev.vars.example
# ======================== # ========================
# 测试产物 (Testing) # 测试产物 (Testing)
+1 -5
View File
@@ -1,7 +1,3 @@
{ {
"recommendations": [ "recommendations": ["svelte.svelte-vscode", "esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
"svelte.svelte-vscode",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint"
]
} }
+28 -10
View File
@@ -23,24 +23,32 @@ cd blogflare
pnpm install pnpm install
``` ```
### 2. 初始化本地数据库 ### 2. 初始化与同步数据库迁移
本项目在本地开发时依赖 Wrangler 模拟 D1 数据库环境。请运行以下命令初始化数据库表和测试数据: 本项目全面采用 Cloudflare D1 规范化迁移链体系。不管是初次安装还是升级扩展,只需应用增量迁移(`0000_initial.sql`、`0001_add_series.sql` 等)即可自动实现幂等同步:
`0000_initial.sql` 同时兼容空数据库和旧版 `schema.sql` 已初始化的数据库。生产升级前仍应先创建 D1 备份;不要再对生产库执行已移除的破坏性 `schema.sql`。
#### 本地开发环境同步:
```bash ```bash
pnpm dlx wrangler d1 execute blogflare-db --local --file=./schema.sql pnpm run db:migrate:local
# 或直接运行 wrangler: pnpm exec wrangler d1 migrations apply blogflare-db --local
``` ```
如果你已经初始化过数据库,请不要重新执行会重建表的 `schema.sql`,而应应用增量迁移: 如果需要强制清空本地开发数据库并重新从初始状态加载迁移数据,可以运行:
```bash ```bash
pnpm exec wrangler d1 migrations apply blogflare-db --local pnpm run db:reset:local
``` ```
部署新版本前,再将同一批迁移应用到远端数据库: #### 部署与生产远端库同步:
部署更新或正式发布之前,请将完整的迁移链条应用到云端 D1 远端数据库中:
```bash ```bash
pnpm exec wrangler d1 migrations apply blogflare-db --remote pnpm run db:migrate:remote
# 或直接运行 wrangler: pnpm exec wrangler d1 migrations apply blogflare-db --remote
``` ```
### 3. 启动本地开发服务器 ### 3. 启动本地开发服务器
@@ -52,6 +60,15 @@ pnpm run dev
pnpm run dev -- --open pnpm run dev -- --open
``` ```
### 4. 配置后台认证
生产环境的 `/admin` 路由强制验证 Cloudflare Access JWT。请在 Cloudflare Pages 项目中配置以下两个加密变量;缺少任意一项时后台会拒绝访问:
- `CF_ACCESS_TEAM_DOMAIN`:例如 `https://your-team.cloudflareaccess.com`
- `CF_ACCESS_AUD`:Access Application 的 Audience (AUD) Tag
本地生产预览可复制 `.dev.vars.example` 为 `.dev.vars` 并填入真实值。开发服务器会保留仅限 `dev` 模式的本地认证旁路。
## 📦 构建与部署 ## 📦 构建与部署
### 构建项目 ### 构建项目
@@ -67,13 +84,14 @@ pnpm run build
项目已经配置了 `@sveltejs/adapter-cloudflare`,可以通过连接 GitHub/GitLab 仓库到 Cloudflare Pages 实现自动构建部署,或者使用 Wrangler CLI 进行手动发布: 项目已经配置了 `@sveltejs/adapter-cloudflare`,可以通过连接 GitHub/GitLab 仓库到 Cloudflare Pages 实现自动构建部署,或者使用 Wrangler CLI 进行手动发布:
```bash ```bash
pnpm dlx wrangler pages deploy .svelte-kit/cloudflare pnpm exec wrangler pages deploy .svelte-kit/cloudflare
``` ```
*(注意:正式部署前请确保在 Cloudflare 仪表盘中创建了对应的 D1 数据库,并绑定到项目中)*
_(注意:正式部署前请确保在 Cloudflare 仪表盘中创建了对应的 D1 数据库,并绑定到项目中)_
## 🛠️ 核心技术栈 ## 🛠️ 核心技术栈
- [SvelteKit](https://kit.svelte.dev/) - [SvelteKit](https://kit.svelte.dev/)
- [Cloudflare Pages](https://pages.cloudflare.com/) & [Cloudflare D1](https://developers.cloudflare.com/d1/) - [Cloudflare Pages](https://pages.cloudflare.com/) & [Cloudflare D1](https://developers.cloudflare.com/d1/)
- [Vite](https://vitejs.dev/) - [Vite](https://vitejs.dev/)
- Markdown 解析: `marked`, `highlight.js`, `dompurify`, `mdsvex` - Markdown 解析与净化: `marked`, `highlight.js`, `sanitize-html`, `mdsvex`
+2 -1
View File
@@ -10,6 +10,7 @@ const gitignorePath = path.resolve(import.meta.dirname, '.gitignore');
export default defineConfig( export default defineConfig(
includeIgnoreFile(gitignorePath), includeIgnoreFile(gitignorePath),
{ ignores: ['scratch/**', 'worker-configuration.d.ts'] },
js.configs.recommended, js.configs.recommended,
ts.configs.recommended, ts.configs.recommended,
svelte.configs.recommended, svelte.configs.recommended,
@@ -20,7 +21,7 @@ export default defineConfig(
rules: { rules: {
// typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects. // typescript-eslint strongly recommend that you do not use the no-undef lint rule on TypeScript projects.
// see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors // see: https://typescript-eslint.io/troubleshooting/faqs/eslint/#i-get-errors-from-the-no-undef-rule-about-global-variables-not-being-defined-even-though-there-are-no-typescript-errors
"no-undef": 'off' 'no-undef': 'off'
} }
}, },
{ {
+30 -29
View File
@@ -3,53 +3,54 @@
"private": true, "private": true,
"version": "0.0.1", "version": "0.0.1",
"type": "module", "type": "module",
"packageManager": "pnpm@11.20.0",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"build": "wrangler types && vite build", "build": "wrangler types --check && vite build",
"preview": "wrangler pages dev .svelte-kit/cloudflare --port 4173", "preview": "wrangler pages dev .svelte-kit/cloudflare --port 4173",
"prepare": "svelte-kit sync || echo ''", "prepare": "svelte-kit sync",
"check": "wrangler types && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "wrangler types --check && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .", "lint": "prettier --check . && eslint .",
"format": "prettier --write .", "format": "prettier --write .",
"gen": "wrangler types" "test": "vitest run",
"ci": "pnpm run check && pnpm run lint && pnpm run test && pnpm run build",
"gen": "wrangler types",
"db:migrate:local": "wrangler d1 migrations apply blogflare-db --local",
"db:migrate:remote": "wrangler d1 migrations apply blogflare-db --remote",
"db:reset:local": "rm -rf .wrangler/state/v3/d1 && wrangler d1 migrations apply blogflare-db --local"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^10.0.1", "@eslint/js": "^10.0.1",
"@sveltejs/adapter-cloudflare": "^7.2.8", "@sveltejs/adapter-cloudflare": "^7.2.9",
"@sveltejs/kit": "^2.63.0", "@sveltejs/kit": "^2.70.2",
"@sveltejs/vite-plugin-svelte": "^7.1.2", "@sveltejs/vite-plugin-svelte": "^7.2.0",
"@types/dompurify": "^3.2.0", "@types/node": "^24.13.3",
"@types/node": "^24", "@types/sanitize-html": "2.16.1",
"eslint": "^10.4.1", "eslint": "^10.8.0",
"eslint-config-prettier": "^10.1.8", "eslint-config-prettier": "^10.1.8",
"eslint-plugin-svelte": "^3.19.0", "eslint-plugin-svelte": "^3.22.0",
"globals": "^17.6.0", "globals": "^17.9.0",
"mdsvex": "^0.12.7", "mdsvex": "^0.12.8",
"prettier": "^3.8.3", "prettier": "^3.9.6",
"prettier-plugin-svelte": "^4.1.0", "prettier-plugin-svelte": "^4.1.1",
"svelte": "^5.56.1", "svelte": "^5.56.8",
"svelte-check": "^4.6.0", "svelte-check": "^4.7.4",
"typescript": "^6.0.3", "typescript": "^6.0.3",
"typescript-eslint": "^8.60.1", "typescript-eslint": "^8.66.0",
"vite": "^8.0.16", "vite": "^8.2.0",
"wrangler": "^4.97.0" "vitest": "4.1.10",
"wrangler": "^4.119.0"
}, },
"dependencies": { "dependencies": {
"@fancyapps/ui": "^6.1.14", "@fancyapps/ui": "^6.1.14",
"dompurify": "^3.4.11",
"highlight.js": "^11.11.1", "highlight.js": "^11.11.1",
"marked": "^18.0.6", "jose": "6.2.8",
"marked": "^18.0.9",
"marked-highlight": "^2.2.4", "marked-highlight": "^2.2.4",
"sanitize-html": "2.17.6",
"smol-toml": "^1.7.1", "smol-toml": "^1.7.1",
"tocbot": "^4.36.8", "tocbot": "^4.36.8",
"yaml": "^2.9.0" "yaml": "^2.9.0"
},
"pnpm": {
"onlyBuiltDependencies": [
"esbuild",
"workerd",
"sharp"
]
} }
} }
+990 -655
View File
File diff suppressed because it is too large. Load diff
+3
View File
@@ -2,3 +2,6 @@ allowBuilds:
workerd: true workerd: true
sharp: true sharp: true
esbuild: true esbuild: true
overrides:
cookie: 0.7.2
undici: 7.29.0
+1 -3
View File
@@ -11,8 +11,6 @@
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"moduleResolution": "bundler", "moduleResolution": "bundler",
"types": [ "types": ["./worker-configuration.d.ts"]
"./worker-configuration.d.ts"
]
} }
} }
+2 -1
View File
@@ -8,7 +8,8 @@ export default defineConfig({
sveltekit({ sveltekit({
compilerOptions: { compilerOptions: {
// Force runes mode for the project, except for libraries. Can be removed in svelte 6. // Force runes mode for the project, except for libraries. Can be removed in svelte 6.
runes: ({ filename }) => filename.split(/[/\\]/).includes('node_modules') ? undefined : true runes: ({ filename }) =>
filename.split(/[/\\]/).includes('node_modules') ? undefined : true
}, },
adapter: adapter(), adapter: adapter(),
preprocess: [mdsvex({ extensions: ['.svx', '.md'] })], preprocess: [mdsvex({ extensions: ['.svx', '.md'] })],
+2186 -882
View File
File diff suppressed because it is too large. Load diff
+18 -5
View File
@@ -1,16 +1,29 @@
{ {
"$schema": "./node_modules/wrangler/config-schema.json", "$schema": "./node_modules/wrangler/config-schema.json",
"name": "blogflare", "name": "blogflare",
"compatibility_date": "2026-07-12", "compatibility_date": "2026-08-07",
"compatibility_flags": [ "compatibility_flags": ["nodejs_compat"],
"nodejs_als"
],
"pages_build_output_dir": ".svelte-kit/cloudflare", "pages_build_output_dir": ".svelte-kit/cloudflare",
"secrets": {
"required": ["CF_ACCESS_TEAM_DOMAIN", "CF_ACCESS_AUD"]
},
"observability": {
"enabled": true,
"logs": {
"enabled": true,
"head_sampling_rate": 1
},
"traces": {
"enabled": true,
"head_sampling_rate": 0.01
}
},
"d1_databases": [ "d1_databases": [
{ {
"binding": "DB", "binding": "DB",
"database_name": "blogflare-db", "database_name": "blogflare-db",
"database_id": "8d03662c-fb92-43f7-82cf-4a8efbb96617" "database_id": "8d03662c-fb92-43f7-82cf-4a8efbb96617",
"migrations_dir": "migrations"
} }
], ],
"r2_buckets": [ "r2_buckets": [