perf(client): restore bundle guardrails

This commit is contained in:
2026-07-16 19:35:51 +08:00
parent 40c6de5a06
commit 990add97f8
6 changed files with 69 additions and 17 deletions
+33
View File
@@ -0,0 +1,33 @@
name: CI
on:
pull_request:
push:
branches:
- dev
- main
- test
workflow_dispatch:
jobs:
verify:
name: Quality and Bundle Budgets
runs-on: gitea-label
container:
image: cozsweet-act-runner-node24-docker:latest
env:
NEXT_TELEMETRY_DISABLED: "1"
SENTRY_UPLOAD_SOURCEMAPS: "0"
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run quality checks
run: pnpm quality
- name: Enforce bundle budgets
run: pnpm perf:bundle:check
-7
View File
@@ -18,16 +18,10 @@ jobs:
SENTRY_UPLOAD_SOURCEMAPS: "0"
steps:
- name: Skip quality gate for test branch
if: ${{ github.ref == 'refs/heads/test' }}
run: echo "Quality gate is disabled for the test branch."
- name: Checkout
if: ${{ github.ref != 'refs/heads/test' }}
uses: actions/checkout@v4
- name: Install dependencies
if: ${{ github.ref != 'refs/heads/test' }}
run: pnpm install --frozen-lockfile
- name: Run quality checks
@@ -35,7 +29,6 @@ jobs:
run: pnpm quality
- name: Enforce bundle budgets
if: ${{ github.ref != 'refs/heads/test' }}
run: pnpm perf:bundle:check
publish:
+4 -4
View File
@@ -8,14 +8,14 @@
| Workflow | 触发时机 | 职责 |
| --- | --- | --- |
| `.gitea/workflows/ci.yml` | `dev``main``test` push / PR | 安装依赖、Lint、单元测试、Next.js 构建 |
| `.gitea/workflows/ci.yml` | `dev``main``test` push / PR | 安装依赖、执行完整质量检查并校验 bundle 预算 |
| `.gitea/workflows/docker-image.yml` | `main``test` push / 手动触发 | 构建 Docker 镜像、推送到镜像仓库,并通过 SSH 部署 |
这样可以避免所有开发分支都发布镜像,并确保生产镜像通过发布门禁。
`main` 分支发布前会执行 Docker workflow 内的质量和 bundle 门禁。`test`
分支为快速部署测试环境,会跳过该门禁;独立的 `ci.yml` 仍会照常执行测试分支检查,
但不会阻塞测试镜像构建与部署
`main` 分支发布前会执行 Docker workflow 内的完整质量和 bundle 门禁。`test`
分支为快速部署测试环境,会跳过完整质量检查,但仍必须通过 bundle 预算;独立的
`ci.yml` 会同时执行完整检查并提供测试结果
## 必需 Secrets
+9 -5
View File
@@ -1,6 +1,6 @@
# Performance baseline
Baseline date: 2026-07-15
Baseline date: 2026-07-16
Next.js: 16.2.7 (Turbopack)
@@ -30,10 +30,10 @@ Compressed sizes below are Turbopack module estimates. `Eager` is the route's sy
| Route | Direct-import baseline | Current eager baseline | Change | Current async baseline |
| --- | ---: | ---: | ---: | ---: |
| `/splash` | 646.2 KiB | 599.7 KiB | -46.5 KiB | 49.2 KiB |
| `/chat` | 669.8 KiB | 637.8 KiB | -32.0 KiB | 49.6 KiB |
| `/subscription` | 658.4 KiB | 616.9 KiB | -41.5 KiB | 20.6 KiB |
| `/tip` | 651.6 KiB | 610.9 KiB | -40.7 KiB | 20.6 KiB |
| `/splash` | 646.2 KiB | 599.9 KiB | -46.3 KiB | 49.2 KiB |
| `/chat` | 669.8 KiB | 640.7 KiB | -29.1 KiB | 49.6 KiB |
| `/subscription` | 658.4 KiB | 617.3 KiB | -41.1 KiB | 20.6 KiB |
| `/tip` | 651.6 KiB | 611.2 KiB | -40.4 KiB | 20.6 KiB |
The earlier direct-import pass replaced root `@/utils` and `@/data/storage`
barrel imports with symbol-level module paths. The current Client-boundary pass
@@ -42,6 +42,10 @@ provider imports, and loads the Dexie-backed chat repository through a dynamic
import. UA Parser remains an intentional eager dependency because the app still
requires its general browser, OS, and device detection behavior.
The 2026-07-16 verification also prevents runtime imports from the root
repository and storage barrels. This keeps unrelated repositories from turning
the intentionally async Dexie path eager when a new feature is added.
Module loading baseline:
| Module | Before | Baseline |
+22
View File
@@ -5,6 +5,28 @@ import nextTs from "eslint-config-next/typescript";
const eslintConfig = defineConfig([
...nextVitals,
...nextTs,
{
files: ["src/**/*.{ts,tsx}"],
rules: {
"no-restricted-imports": [
"error",
{
paths: [
{
name: "@/data/repositories",
message:
"Import the concrete repository module so unrelated browser storage stays out of the client graph.",
},
{
name: "@/data/storage",
message:
"Import the concrete storage module so unrelated persistence code stays out of the client graph.",
},
],
},
],
},
},
{
files: ["src/app/**/*.{ts,tsx}"],
ignores: ["src/app/api/**", "src/app/**/route.ts"],
+1 -1
View File
@@ -2,7 +2,7 @@ import type {
FeedbackSubmitResponse,
SubmitFeedbackInput,
} from "@/data/dto/feedback";
import { getFeedbackRepository } from "@/data/repositories";
import { getFeedbackRepository } from "@/data/repositories/feedback_repository";
import type { Result } from "@/utils/result";
export function submitFeedback(