Skip to content

品牌首页 apps/home

natlan.io 裸域上的静态首页,生产部署 https://natlan.io/

它不是框架应用:一份手写的自包含 index.html、一个模块 Worker、一个 Svelte 岛, 外加一个把网络数据烘焙进 HTML 的构建期脚本。艺术方向见 brand-identity.md

1. 组成

文件是什么
index.html整个页面,自包含:内联 CSS + 一段内联脚本。设计令牌与共享层同源,另有台地灰阶
index.js模块 Worker,负责路由与响应头
fleet-widget/Svelte 岛的源码,构建产出 fleet.bundle.js
fleet.bundle.js岛的构建产物(已提交,Worker 作为文本模块打包)
bake.js把网络数据快照烘焙进 index.html
world-land.geojson岛在运行时取的陆地轮廓(apps/control/static/ 那份的副本)
canyonlands.jpghero 出处弹层的照片(au_ears / Flickr,CC BY-SA 2.0,弹层内已标注)
favicon.svg与控制台的 src/lib/assets/favicon.svg 保持一致
Green_River_Overlook_Ekker_Butte.jpg地形取景参考原图

2. Worker 路由

index.js 只处理 GET / HEAD,其余返回 405。

路径响应Cache-Control
/index.htmlpublic, max-age=300
/favicon.svgfaviconmax-age=86400
/fleet.jsfleet.bundle.jsmax-age=300
/world-land.geojson陆地轮廓max-age=86400
/canyonlands.jpghero 照片max-age=2592000
/robots.txt生成
/sitemap.xml生成(单页一条 <url>max-age=3600
/nodes/*302 → 控制台
其他302 → /

改动页面内容时记得把 SITEMAP 里的 <lastmod> 往前推。

3. 三层数据,逐层降级

首页的机群地图与统计条带有三层来源,任何一层失效都不会让页面坏掉:

来源何时生效
① 烘焙快照bake.js 写进 index.html始终存在。无 JS 也完整成立
② 内联脚本刷新GET /control/v1/public/map页面加载后。fetch 失败就保留快照
③ FleetMap 岛GET /control/v1/public/fleet岛脚本挂载成功后,覆盖静态回退

这是首页唯一的 JS 依赖策略,也是它能做成纯静态的原因。

岛在挂载前会先把 fallback 区块的高度冻结到容器上,避免换入时下方内容跳动 (2026-07 的 CWV 报告里这一段 CLS 0.296)。

4. FleetMap 岛

fleet-widget/ 挂载的是 $ui 里的 FleetMap.svelte——与控制台渲染的是同一个 组件,因此首页的地图不可能与控制台漂移。

两个值得记住的细节:

  • 岛的入口直接引 $ui/host.svelte 而不走桶文件。桶里 re-export 了 CapCheck, 它的 ?url 资源(Cap 的 WASM 与 pako)会被一并 emit 到产物目录——JS 侧摇得掉, 文件却留下了。首页用不到验证码。
  • 注入的宿主是两个常量locale: entheme: dark)而不是响应式实例:首页 没有语言切换器,明暗全交给 CSS 的 prefers-color-schemetheme.mode 只被图表 当重绘信号,首页只挂地图,取值不影响渲染。

合仓前这个岛要靠四个 shim 桩掉控制台的 $lib/apitoasturlstate$app/environment,还得写 CSS 把用不到的按钮藏起来。共享库的可选 prop 契约把这些 全消掉了,产物小了 47%。

5. hero 地形

hero 背景的等高线是真实地形:从 AWS terrain-tiles DEM 烘焙的 Canyonlands Island in the Sky 一带高程(hypsometric 填充 + index contours),标出了 Green River Overlook——ⓘ 徽标里那张 CC BY-SA 照片正是在那里拍的。

重新生成:node fleet-widget/scripts/terrain.mjs,取景由脚本里的 ANCHOR_FX/FY 控制。

6. 部署

Cloudflare Git 关联 Workernatlan-io-home):

Build commandnpm run build:home(重建 fleet.bundle.js
Deploy commandnpx wrangler deploy -c apps/home/wrangler.jsonc
Build watch pathsapps/home/* + ui/*

wrangler.jsonc 里的 rules 把 html / svg / geojson / *.bundle.js 当文本模块、 jpg 当二进制数据模块打包进 Worker;workers_dev: false 关掉第二入口。

裸域自定义域经 PUT /accounts/{account}/workers/domains 绑定,跨部署保持。

⚠️ bake.js 不在构建流程里。 Git 关联不会替你跑它。烘焙快照过期时要手工 node apps/home/bake.js 并提交。见 guides/refresh-home-snapshot.md

手工部署仍然可用:npx wrangler deploy -c apps/home/wrangler.jsonc