perf: streamline billing panel bootstrap
Remove the redundant billing account read, cache packages for one minute, prefetch the billing chunk, and parallelize independent package reads. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ const membershipLib = readProjectFile("src/lib/membership.ts");
|
||||
const nextConfig = readProjectFile("next.config.ts");
|
||||
const pageSource = readProjectFile("src/app/(app)/page.tsx");
|
||||
const tabsSource = readProjectFile("src/components/ui/tabs.tsx");
|
||||
const packagesRouteSource = readProjectFile("src/app/api/payment/packages/route.ts");
|
||||
|
||||
function countMatches(source: string, pattern: RegExp) {
|
||||
return source.match(pattern)?.length ?? 0;
|
||||
@@ -34,21 +35,33 @@ test("membership routes are gone and billing loads without a spinner", () => {
|
||||
assert.match(nextConfig, /destination: "\/\?settings=billing&tab=orders"/);
|
||||
});
|
||||
|
||||
test("membership page loads account, packages and redeem endpoints without fetching orders", () => {
|
||||
// 原值: 会员页不请求 /api/payment/orders
|
||||
// 新值: 挂载只并发账户与套餐;订单仅在 orders 页签拉取
|
||||
// 原因: 订单记录改成分区内页签,不能一打开就打列表接口
|
||||
test("membership page loads packages and redeem endpoints without an unused account request", () => {
|
||||
// 原值: 挂载并发 /api/account 与套餐接口。
|
||||
// 新值: 挂载只取有实际用途的套餐;账户余额由首页 bootstrap 提供,兑换/支付成功后才刷新账户。
|
||||
// 原因: BUG-1022;重复账户请求拖慢首开且结果不作为初始渲染来源。
|
||||
assert.match(hookSource, /fetch\("\/api\/account"/);
|
||||
assert.match(hookSource, /fetch\("\/api\/payment\/packages"/);
|
||||
assert.match(hookSource, /fetchPaymentPackages/);
|
||||
assert.match(hookSource, /const refreshed = await fetchAccountData\(\);/);
|
||||
assert.match(hookSource, /fetch\("\/api\/payment\/epay\/create"/);
|
||||
assert.match(hookSource, /fetch\(`\/api\/payment\/epay\/status\?orderNo=/);
|
||||
assert.match(hookSource, /fetch\("\/api\/redeem"/);
|
||||
assert.match(hookSource, /await Promise\.allSettled\(\[fetchAccountData\(\), fetchPackages\(\)\]\)/);
|
||||
const mountStart = hookSource.indexOf("await Promise.allSettled");
|
||||
const mountEnd = hookSource.indexOf("}, [fetchAccountData, fetchPackages]);");
|
||||
const mountStart = hookSource.indexOf("void fetchPackages()");
|
||||
const mountEnd = hookSource.indexOf("}, [fetchPackages]);");
|
||||
const mountEffect = hookSource.slice(mountStart, mountEnd);
|
||||
assert.doesNotMatch(mountEffect, /fetchOrders|\/api\/payment\/orders/);
|
||||
assert.doesNotMatch(mountEffect, /fetchAccountData|fetchOrders|\/api\/payment\/orders/);
|
||||
assert.match(panelSource, /if \(value === "orders"\) void fetchOrders\(\)/);
|
||||
assert.match(readProjectFile("src/lib/payment-packages-cache.ts"), /PAYMENT_PACKAGES_CACHE_TTL_MS = 60_000/);
|
||||
});
|
||||
|
||||
test("packages route reads feature flags and products in parallel before dependent entitlements", () => {
|
||||
// 原值: feature flags 与商品查询串行。
|
||||
// 新值: 两项互不依赖的读取用 Promise.all;权益仍在拿到 productIds 后查询。
|
||||
// 原因: BUG-1022;缩短套餐接口首响应,不改变权限与权益依赖顺序。
|
||||
assert.match(packagesRouteSource, /const \[flags, productsResult\] = await Promise\.all\(\[/);
|
||||
assert.match(packagesRouteSource, /loadRuntimeFeatureFlags\(\["billing\.subscriptions"\]\)/);
|
||||
assert.match(packagesRouteSource, /createAdminSupabaseClient\(\)/);
|
||||
assert.match(packagesRouteSource, /const productIds = products\.map/);
|
||||
assert.ok(packagesRouteSource.indexOf("const productIds = products.map") < packagesRouteSource.indexOf("product_entitlements"));
|
||||
});
|
||||
|
||||
test("creates orders with productId and opens the signed cashier URL safely", () => {
|
||||
|
||||
Reference in New Issue
Block a user