Skip to content

runner 的站内导航把 ?api= 从地址栏抹掉:刷新/分享该 URL 会静默退回空的本地打包加载器 #3578

Description

@yinlianghui

越界发现,记录于 #3537(给 runner 补 api 查询参数文档)期间。未在该 PR 中顺手修改 —— 那是纯文档单,这里要动的是 packages/runner/src/App.tsx 的实现。PR #3537 已把这一行为如实写成注意事项,但它本身更像缺陷而不是设计,故另立单。

事实(origin/main,file:line)

  1. 加载器只在挂载时决定一次 —— packages/runner/src/App.tsx:44-57,useMemo(..., []),依赖数组为空:

    const loader = useMemo(() => {
      const params = new URLSearchParams(window.location.search);
      const apiUrl = params.get('api');
      if (apiUrl) return new NetworkLoader(apiUrl);
      return new LocalBundleLoader();
    }, []);
  2. 站内跳转只 push 路径,不带 query —— App.tsx:73-77:

    const handleNavigate = useCallback((to: string) => {
      window.history.pushState({}, '', to);
      ...

    to 来自侧栏导航项的 item.path(packages/runner/src/LayoutRenderer.tsx:104-105a href={item.path}LayoutRenderer.tsx:151-157handleNavClickonNavigate(path)),是裸路径。

后果

?api=https://backend.example.com/api 打开 runner → 正常走 NetworkLoader;点一次侧栏导航后,地址栏变成 /customers(?api= 没了)。当前会话不受影响(loader 实例已 memo 住),但:

  • 刷新(F5)params.get('api') 为 null → 退回 LocalBundleLoader;而 src/app-data/ 在正常安装里是空的(gitignore),于是所有加载返回 null,页面变成 Page not found / 兜底欢迎页。
  • 复制地址栏分享给同事 → 对方拿到的是不带后端的 URL,复现不了你看到的东西。

失败现场不指认根因:没有任何提示说「你刚才那个 API 基址丢了」,控制台只会打印 📦 Using Local Bundle Loader

可选方向(不预设结论)

  1. handleNavigate 保留当前 query string(pushState({}, '', to + window.location.search))—— 最小改动,?api= 全程可见、可分享、刷新可复现。
  2. 把 API 基址从 query 提到 sessionStorage/localStorage,query 只作为一次性入口 —— 但会引入「地址栏与实际后端不一致」的新歧义,且与 ADR-0054 C3「可寻址状态放 URL」的口径相反。
  3. 判定为设计如此(query 只是本地调试开关),那就只留 docs(runner): runner 真正的 API 基址配置面是 api 查询参数,但全仓文档零处记载 #3537 的文档注意事项,本单关掉。

按 ADR-0054 C3 的分类,「当前指向哪个后端」是典型的可寻址状态(用户会分享、刷新后期待还在),方向 1 与之最一致;但这是维护者判断,故不预设。


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions