Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/manifest-site-url-env.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@app/ratewise': patch
---

staging 等替代網域安裝 PWA 時 manifest scope 不再指向正式站:scope/start_url 改由 VITE_SITE_URL 環境變數驅動(含 trailing-slash 正規化),未設定時輸出與正式站完全相同。
14 changes: 12 additions & 2 deletions apps/ratewise/scripts/generate-manifest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ const currencyCount = [...constantsContent.matchAll(/^\s+([A-Z]{3}):\s*\{/gm)].l

const versioned = (path) => `${path}?v=${VERSION_TOKEN}`;

// scope/start_url 以 VITE_SITE_URL 環境變數驅動(與 seo-metadata canonical 同一 SSOT),
// 未設定時回退正式站 APP_INFO.siteUrl;staging 等替代網域部署設定該變數即可,禁止硬編網域。
// 正規化行為對齊 seo-paths.ts 的 normalizeSiteUrl(trim+補尾斜線);無法直接 import 複用:
// seo-paths.ts 內部以無副檔名路徑 import './app-info',Node Type Stripping 不解析副檔名。
function normalizeSiteUrl(value) {
const trimmed = value.trim();
return trimmed.endsWith('/') ? trimmed : `${trimmed}/`;
}
const siteUrl = normalizeSiteUrl(process.env.VITE_SITE_URL || APP_INFO.siteUrl);

const manifest = {
name: APP_INFO.name,
short_name: APP_MANIFEST.shortName,
Expand All @@ -39,8 +49,8 @@ const manifest = {
display: 'standalone',
// 絕對 HTTPS scope/start_url:避免獨立 PWA partition + Chrome HTTPS-First 在啟動時以 http 語意解析。
// id 維持相對(id 變更會被視為新 PWA 身分,破壞既有安裝更新連續性)。
scope: APP_INFO.siteUrl,
start_url: APP_INFO.siteUrl,
scope: siteUrl,
start_url: siteUrl,
id: '/ratewise/',
orientation: 'portrait-primary',
categories: ['finance', 'utilities', 'productivity'],
Expand Down
13 changes: 11 additions & 2 deletions apps/ratewise/src/config/__tests__/build-scripts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { existsSync, readdirSync, statSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import path from 'node:path';
import { pathToFileURL } from 'node:url';
import { APP_INFO } from '../app-info';

async function readPackageJson() {
const packageJsonPath = path.resolve(__dirname, '../../../package.json');
Expand Down Expand Up @@ -270,11 +271,19 @@ describe('ratewise build scripts', () => {
start_url: string;
};

expect(manifestGenerator).toContain('scope: APP_INFO.siteUrl');
expect(manifestGenerator).toContain('start_url: APP_INFO.siteUrl');
// scope/start_url 由 VITE_SITE_URL 環境變數驅動(staging 等替代網域),未設定時回退正式站 SSOT,
// 正規化必須複用 seo-paths 的 normalizeSiteUrl 避免行為分歧。
expect(manifestGenerator).toContain(
'normalizeSiteUrl(process.env.VITE_SITE_URL || APP_INFO.siteUrl)',
);
expect(manifestGenerator).toContain('scope: siteUrl');
expect(manifestGenerator).toContain('start_url: siteUrl');
expect(manifest.scope).toMatch(/^https:\/\//);
expect(manifest.start_url).toMatch(/^https:\/\//);
expect(manifest.scope).toBe(manifest.start_url);
// committed manifest 必為正式站:堵住 env 污染下(VITE_SITE_URL 指向 staging)
// 重新生成並誤 commit staging URL 仍全綠的缺口。
expect(manifest.scope).toBe(APP_INFO.siteUrl);
});

it('should not force React ecosystem packages into manual chunks', async () => {
Expand Down
7 changes: 6 additions & 1 deletion docs/dev/002_development_reward_penalty_log.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> 版本:outline-v2-ultra
> 原則:每筆只保留日期、ID、原因、解法。
> 本次分數變化:+2(reward 2、penalty 0、neutral 1)|累計總分:+149
> 本次分數變化:+1(reward 1、penalty 0、neutral 0)|累計總分:+150

## 新增模板(4 行)

Expand All @@ -13,6 +13,11 @@

## 條目(新→舊)

- 日期:2026-07-06
- ID:reward-rw-602-manifest-site-url-env
- 原因:generate-manifest 的 scope/start_url 硬編 APP_INFO.siteUrl(app.haotool.org),staging 等替代網域部署時 manifest scope 跨網域、PWA 安裝行為異常(#602;字體 @font-face 被 Beasties 修剪部分經 PM 裁決移交 #616 處理)
- 解法:scope/start_url 改由 VITE_SITE_URL 環境變數驅動+normalizeSiteUrl 正規化(行為對齊 seo-paths;直接 import 因該檔無副檔名 import 在 Node Type Stripping 下 ERR_MODULE_NOT_FOUND,以註解標明),未設定時回退正式站;committed manifest 補「必為正式站」JSON 斷言堵 env 污染誤 commit,generate:deterministic 冪等零 diff 實證

- 日期:2026-07-06
- ID:reward-rw-600-anchor-scroll-mt-safe-area
- 原因:#605 修了 sticky 返回列 safe-area 但錨點目標 `scroll-mt-20` 固定 80px 未連動,standalone 下 sticky 列變高(+59px)後隱私目錄與 Guide 步驟跳轉被遮蔽(#600 連動項)
Expand Down
Loading