本仓为 private。本篇含内部部署细节,禁止复制到对外文档 / 开源材料 / 公开仓库。 无论对内对外,AK/SK 密钥一律不写进任何文档或代码,只从既有部署脚本引用。
| 内容 | 托管方 | 说明 |
|---|---|---|
| 依赖(lit / @lit-labs/*) | FMODE Repose | 静态依赖仓,从 npm 下原始 ESM 原样同步,按版本目录化,全业务共享 |
| 业务码(index.html / js) | OBS + CDN | obsutil 同步 src/ 到华为云 OBS,public-read,CDN 加速 |
存放布局
/npm/lit/v3.x.x/ # lit 运行时(原始 ESM)
/npm/@lit-labs/context/vx/ # context
/npm/@lit-labs/signals/vx/ # signals
/npm/@lit-labs/router/vx/ # router
/npm/importmap/lit-v3.json # 公共 importmap(全业务复用)
硬性要求
.js 响应的 Content-Type 必须 text/javascript(否则浏览器拒绝作为模块执行)。/vX.Y.Z/),升级 = 新增目录 + 改 importmap 版本号,不覆盖旧版本。同步方式:把 node_modules/lit、node_modules/@lit-labs/* 原样上传到 Repose 对应版本目录。
(仓库内提供同步脚本入口占位,实际凭据从环境 / 既有脚本注入。)
公共 importmap(托管在 Repose,业务引用)
{
"imports": {
"lit": "/npm/lit/v3.2.1/lit.js",
"lit/": "/npm/lit/v3.2.1/",
"lit/decorators.js": "/npm/lit/v3.2.1/decorators.js",
"@lit-labs/signals": "/npm/@lit-labs/signals/v0.1.3/index.js",
"@lit-labs/context": "/npm/@lit-labs/context/v0.5.1/index.js",
"@lit-labs/router": "/npm/@lit-labs/router/v0.2.0/router.js"
}
}
版本号以仓库实际落地为准,此处为示例形态。升级依赖 = 追加新路径 + 改这里的版本段。
入口 index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<base href="/<project>/" /><!-- 二级路径部署必须;根部署可省略或 "/" -->
<link rel="importmap" href="..."><!-- 见下 -->
<script type="importmap" src="<公共 importmap URL>"></script>
</head>
<body>
<app-root></app-root>
<script type="module" src="./app.js"></script>
</body>
</html>
<script type="importmap" src="<Repose>/npm/importmap/lit-v3.json"></script>。<base href> 决定相对路径基准,子目录部署必须写对。上传(obsutil)
/opt/data/bin/obsutilfmode-app/scripts/deploy.sh),禁止写入本仓文档/代码。典型命令形态:
# 同步业务源码到 OBS 前缀,公开读
obsutil sync ./src/ obs://<bucket>/<project>/ \
-e=obs.cn-south-1.myhuaweicloud.com -acl=public-read -f
index.html 先删后传:sync 按 size+mtime 判 Skip,index.html 名字固定、内容随发布变化,需先 rm 再 cp,避免被 Skip。
静态资源设 Cache-Control:index.html 用 no-cache(保证回退拿到最新),带 hash 的资源可长缓存。
CDN 刷新:上传后调用 CDN refresh(仓库内 scripts/deploy.sh 已接入既有刷新脚本)。刷新范围由传入的 URL 域名决定。
⚠️ CDN 刷新的两个假成功陷阱(实测踩过,详见 routing-best-practices.md 坑 5):
- 域名对号入座:每个加速域有各自的
domain_id与凭证;用错只刷了一个域名, 用户访问的另一个域名照旧是旧内容。未知域名应直接报错,别静默跳过。- SDK 返回结构:
refresh_task是字符串 ID,不是对象。若读成result.refresh_task.id会恒得undefined,脚本照常退出 0(假成功)。 必须对结果做非空断言,任一失败则退出码非 0。刷新用
type: 'directory'(URL 以/结尾)一次覆盖目录,比逐个 file 省事且不易漏。
curl 首页curl 首页 200 只证明 index.html 在;无构建应用白屏的典型原因(某模块 404、MIME 错、
回退没配、相对路径错一个字符)它一个都不覆盖。分层验收:
node --check 无语法/装饰器残留;相对 import 带 .js;
相对目标存在;裸标识符都在 importmap;自定义元素标签含连字符。app.js 跟随相对 import 走完整图,
断言每个文件 200 + Content-Type: text/javascript;importmap 每条目标可达;
深链接返回 200 且内容是 index.html(非 302)。把 1–2 步固化成一条命令纳入部署流程。可复用脚本形态见 routing-best-practices.md 坑 7。
🔎 CDN 冷边缘:新上传的 key 首次被某边缘节点拉取时偶发 404(回源竞争), 重跑一次即消失 —— 验收脚本碰到新 key 的首次 404 不要立刻判故障。
| 规则 | 匹配 | 动作 |
|---|---|---|
| 规则 1 | 命中真实静态资源 | 直接返回该文件 |
| 规则 2 | 路径不存在 | 返回 index.html,状态码 200,禁止 301/302 |
location.pathname,破坏路由参数与微信 OAuth 回调。index.html 设 no-cache,确保回退总是拿到最新壳。#!/usr/bin/env bash
# scripts/deploy.sh —— 无构建,直接同步 src/ 到 OBS,再刷 CDN
set -euo pipefail
PROJECT="${1:?usage: deploy.sh <project>}"
BUCKET="${OBS_BUCKET:?set OBS_BUCKET}" # 例: obs://www-fmode.cn
PREFIX="$PROJECT"
EP="obs.cn-south-1.myhuaweicloud.com"
OBS=/opt/data/bin/obsutil
# 1) index.html 先删后传(防 Skip)+ no-cache
"$OBS" rm "$BUCKET/$PREFIX/index.html" -e="$EP" -f >/dev/null 2>&1 || true
"$OBS" cp ./src/index.html "$BUCKET/$PREFIX/index.html" -e="$EP" -acl=public-read -f \
-meta="Cache-Control:no-cache#Content-Type:text/html; charset=utf-8"
# 2) 其余源码同步
"$OBS" sync ./src/ "$BUCKET/$PREFIX/" -e="$EP" -acl=public-read -f
# 3) 刷新 CDN(调用既有刷新脚本,凭据由该脚本/环境提供)
# node <既有刷新脚本> "https://<cdn-domain>/$PREFIX/"
src/ 即产物。<base href> 与部署前缀一致(同一变量派生,脚本里硬校验)Content-Type: text/javascript + CORS 放行)index.html 已先删后传 + no-cachetype:directory,domain_id 对号入座,读 refresh_task 字符串,失败退出非 0)/users/42)刷新可用(200 且为 index.html)路由 / base / CDN 的完整肺坑与 check 清单见 routing-best-practices.md。