perf(client): restore bundle guardrails
This commit is contained in:
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user