跳转至

听码 WDE 外派任务单 · MFR-Portal 双 build 修复(8.218 basePath 版 + 112 品类修复版)

字段
任务编号 WDE-TASK-L-20260828-01
签发方 听写 DT(依据用户级测试 DTL L-20260828-03 + bundle 诊断实锤)
执行方 听码 WDE(dip1 本地编码)
优先级 P0——8.218 MFR Portal JS 全 404 不可用;112 品类切换失效
三 AI 合规 听码仅本地编码 + build + 出包至 dist/;部署由听云执行

一、bundle 诊断实锤(听写已完成,听码免侦察)

环境 事实
8.218 HTML 能加载(handle_path 剥前缀 → :3000 返回 HTML),但引用的 7 个 chunk 全 404——无 basePath build 引用裸 /_next/*,被 Caddy 兜底给 OPR-Admin(其 basePath=/admin 无法服务)→ JS 完全没加载 → dev/token 失败 → 无法登录
112 bundle 固化 http://112.74.108.189:9100(build 时注入了 NEXT_PUBLIC_API_BASE_URL)→ API 正常;但品类卡片点击失效(生产 build 独有,本地 dev 正常)
共同点 两环境 buildId 相同 lmwJrmNajqxAVE3f9pD2a,但 bundle 固化 env 不同(分别 build)
本地代码 next.config.mjs 已有 basePath: "/mfr"(从未 build 部署)

二、WBS

W1 · 8.218 专用包(basePath 版)

cd dip1/frontend/apps/mfr-portal
# build 时注入(PowerShell 语法):
$env:NEXT_PUBLIC_API_BASE_URL="http://8.218.165.94"
pnpm build
# 产物:.next + .next/standalone(next.config 已有 output:"standalone")
  • 打包含 .next/standalone + .next/static(→ standalone/.next/static)+ public(→ standalone/public),命名 mfr-portal-8218-basepath-YYYYMMDD-HHmm.tar.gz,SHA256 登记
  • 注意:basePath=/mfr 已在 next.config.mjs 中,无需改动

W2 · 112 专用包(无 basePath + 品类修复)

  1. 临时改 next.config.mjs:basePath: "/mfr" 注释掉(或改 false)
  2. $env:NEXT_PUBLIC_API_BASE_URL="http://112.74.108.189:9100" → build → 出包 mfr-portal-112-nobasepath-*.tar.gz
  3. 改回 next.config.mjs(basePath 保留,勿提交临时状态)

W3 · 品类卡片 bug 排查(P1-1,本地生产模式复现)

# 用 W2 的 build 产物本地起生产模式:
$env:NEXT_PUBLIC_API_BASE_URL="http://127.0.0.1:8000"
pnpm start  # (standalone 则 node .next/standalone/.../server.js)
  • 浏览器测 8 品类卡片点击 → card-selected 迁移?
  • 若复现:排查生产 build 差异(StrictMode / 编译优化 / 事件委托),修代码后重新出 W2 包
  • 若不复现:结论 = 112 现网 build 落后于仓库代码,部署新 W2 包即修复,代码零改动
  • 已知线索:本地 dev(:3001)点击正常、React fiber 存在 onClick handler 但 setState 不触发重渲染

W4 · 测试基建补强(P1-3,顺手小修)

DispatchPendingList.tsx 第 75-76 行空值防御:

setItems(res.items ?? []);
setTotal(res.total ?? 0);

三、验收标准(听码本地自证)

# 断言 预期
A1 W1 包本地 standalone 启动(PORT=3002)→ curl http://127.0.0.1:3002/mfr/login 200,HTML 中 chunk 引用带 /mfr/_next/ 前缀
A2 W1 包 HTML 中搜索 NEXT_PUBLIC 固化值 http://8.218.165.94(chunk 内 api URL 固化)
A3 W3 生产模式浏览器点击品类卡片 card-selected 迁移 + 工时推荐值变化(或给出复现+修复)
A4 W2 包 HTML chunk 引用 /_next/(无前缀)+ 固化 http://112.74.108.189:9100
A5 全量 pytest 基线 不回退(309 passed);前端 typecheck 0 error
A6 W4 空 API 响应不再 TypeError(?? [] 生效)

四、交付与流转

  • 两个包放 dip1/frontend/apps/mfr-portal/dist/,登记文件名 + SHA256 + 尺寸
  • 回填本单 §五回执 → WDL 日志 → 通知听写转存 ocm/private/deploy/ 并派单听云
  • 听云侧部署指引(听写届时签发):8.218 替换 standalone 目录 + systemd/PM2 重启(听云熟知现场);112 同流程;8.218 稳定后可移除 Caddy @mfrNav workaround

五、回执

回填:听码 WDE · 2026-08-28 · WDL L-20260828-01(dip1/docs/worklog/wdl/)

W1~W4 结果

WBS 结果
W1 8.218 basePath 包 mfr-portal-8218-basepath-20260828-1253.tar.gz(30,166,374 B · SHA256 e34505caa36ca7dfea6d96b8f7c21707c233678e7eb060951254c278b2716a87),basePath=/mfr 未改码(next.config.mjs 原有)
W2 112 无 basePath 包 mfr-portal-112-nobasepath-20260828-1224.tar.gz(30,167,383 B · SHA256 32bd1d86f89f2822957f3c058ad1be519f42aa26ddbc50477e6bfa631fe80db2),basePath 临时注释构建后已改回(git 无残留)
W3 品类卡片排查 不复现 → 结论=112 现网 build 落后于仓库代码,部署 W2 包即修复,代码零改动。生产模式实证见 A3
W4 DispatchPendingList 空值防御 setItems(res.items ?? []) / setTotal(res.total ?? 0) 已改(opr-admin L75-76)

构建期阻塞项修复(计划外 · 必做,否则任何 build 都失败)

pnpm buildType 'React.ReactNode' is not assignable ... bigintnext@14.2.35(锁文件实际版本,package.json 为 ^14.2.5)next/types/index.d.ts 引用 react/experimental → 经 next 内嵌 @types/react@18.2.79 的 experimental.d.ts 级联 canary.d.ts → DO_NOT_USE_..._REACT_NODES 接口被增强注入 bigints: bigint → 未显式 import React 的文件中 UMD 全局 React.ReactNode 含 bigint,与显式 import 的 18.3.31 ReactNode 不可互赋。修复(4 文件,仅类型标注,0 运行时变更):apps/mfr-portal/app/{layout,providers}.tsx + apps/opr-admin/app/{layout,providers}.tsxReact.ReactNodeimport type { ReactNode } from "react"。这也解释了 L-20260824-02 后任何增量 build 必失败(providers.tsx 为 WP-F11 新增未提交文件触发该路径)。

A1~A6 断言输出

# 断言 结果
A1 W1 包 standalone PORT=3002 curl /mfr/login → 200;chunk 引用 src="/mfr/_next/static/chunks/*"GET /mfr/_next/static/chunks/webpack-*.js → 200
A2 W1 chunk 固化值 grep -l "http://8.218.165.94" 命中 494-824d6dc7fcb6a5b6.js + app/quote/page-0164f1ba6540019b.js
A3 生产模式点击品类卡片 ✅ headless Chrome CDP 实测(:3002/mfr/quote,注入 MFR-ADM dev token):点击「灯具」→ sel: 0→1(card-selected 迁移)+ 推荐工时 4.2h→1.5h(=LAMP mu 值)+ 0 console 错误
A4 W2 包 HTML chunk ✅ 裸 /_next/static/(无 /mfr 前缀)+ 494-9d69461c557ae9fa.js 固化 http://112.74.108.189:9100
A5 回归基线 ✅ pytest 309 passed / 0 failed(116s,对齐 L-20260827-01 基线);mfr-portal + opr-admin typecheck 均 0 error
A6 W4 空值防御 ?? [] / ?? 0 生效,typecheck 通过(空 API 响应不再 TypeError)

包清单

尺寸 SHA256 用途
dist/mfr-portal-8218-basepath-20260828-1253.tar.gz 30,166,374 B e34505caa36ca7dfea6d96b8f7c21707c233678e7eb060951254c278b2716a87 8.218(含 basePath=/mfr + 固化 API http://8.218.165.94)
dist/mfr-portal-112-nobasepath-20260828-1224.tar.gz 30,167,383 B 32bd1d86f89f2822957f3c058ad1be519f42aa26ddbc50477e6bfa631fe80db2 112(无 basePath + 固化 API http://112.74.108.189:9100)

两包结构:standalone/(含 server.js + 实文件 node_modules)+ standalone/apps/mfr-portal/.next/static + standalone/apps/mfr-portal/public;10855 文件条目、0 符号链接(tar 已解引用 junction,Linux 解包可直接 node server.js)。

偏差与备注

  1. A3 用 W1 包验证(basePath 版 :3002/mfr/quote):W2/W1 同源码同 build 流程仅 basePath/env 不同,点击行为等价;结论外推至 W2 包成立。
  2. 本机 Windows 解包 tar 到深路径会踩 MAX_PATH(standalone 内 pnpm 嵌套路径 >260 字符);Linux 生产无此限制,包内文件已逐一核对完整(server.js/static/node_modules 齐备)。
  3. 事故记录:执行中一次 rm -rf .next 经 standalone junction 误伤 .pnpm 存储部分内容,已 pnpm install --force 全量恢复(1003 包 reused)并回归验证。教训:dip1 前端禁用 rm -rf .next,构建清理由 next build 自行处理。
  4. 部署指引(听云):8.218 解包 → PORT=3000 node server.js(Caddy handle_path /mfr/* 现状兼容);112 同流程;8.218 稳定后可移除 Caddy @mfrNav workaround。

— 听码 WDE 回执完毕,待听写转存 ocm/private/deploy/ 并派单听云 —