☰
Home Assistant 前端仓库 Landing Page 全解析:HAOS 首次启动的 “Preparing Home Assistant“ 过渡页与本地开发指南
2026/10/12 2:10:31 网站建设 项目流程
  • 前端
  • 智能家居
  • UI组件

【免费下载链接】frontend

:lollipop: Frontend for Home Assistant

项目地址:https://gitcode.com/gh_mirrors/frontend149/frontend
点击查看免费下载

本文以 landing-page/README.md 为核心骨架,结合 frontend 仓库(Home Assistant 官方前端)中landing-page/目录的源码实现,系统讲解 Home Assistant OS(HAOS)首次启动时下载 Home Assistant Core 期间的过渡页面:它的下载进度条、Supervisor 日志展示、DNS 故障处理、错误处理等核心功能如何工作,以及如何在前端仓库与独立的 landingpage 仓库之间搭建本地开发环境。读完本文,你将掌握这一过渡页的完整技术脉络与一套可复现的开发调试流程。

一、背景:为什么需要 Landing Page

HAOS 在首次启动(initial startup)时,必须先从网络下载 Home Assistant Core,下载完成前整个系统的初始化流程还无法开始。在这一段时间内,需要一个独立于 Core 的轻量页面来向用户反馈进度,这就是 Landing Page 的职责——它负责托管一个 "Preparing Home Assistant"(正在准备 Home Assistant)页面,直到 Core 就绪、浏览器自动跳转进入正式的引导流程(onboarding)。

这个页面并非独立项目,而是以子目录形式存在于本 frontend 仓库中(landing-page/),并且与正式前端共享同一套 UI 组件与国际化基础设施。从 landing-page/src/entrypoint.js 可以看出它的入口非常轻量:先加载ha-landing-page自定义元素,再通过import("../../src/resources/append-ha-style")注入前端仓库共享的基础样式。

整个页面最终渲染在 landing-page/src/html/index.html.template 定义的 HTML 骨架中:页面头部展示favicon-192x192.png图标,正文仅包含一个<ha-landing-page></ha-landing-page>自定义元素,并复用前端仓库的_header、_style_base、_js_base、_preload_roboto、_script_loader等 HTML 模板片段,同时对prefers-color-scheme: dark做了暗色适配。

二、五大核心功能拆解

原文档将 Landing Page 的功能归纳为五类,逐一结合源码展开如下。

1. 下载进度条(Progress bar)

进度条用于直观展示 Home Assistant Core 的下载进度。它的数据来源并非浏览器猜测,而是由 Supervisor 的任务系统提供:

  • 页面轮询/supervisor-api/jobs/info接口(见 landing-page/src/data/supervisor.ts),在返回的任务列表中查找名为home_assistant_core_install的任务;
  • 取到该任务后,用其progress字段(0~100 的浮点数)更新进度条;取不到则把进度重置为-1,此时进度条显示为不确定(indeterminate)状态(见 landing-page/src/ha-landing-page.ts)。

页面顶部文案来自国际化文件 src/translations/en.json,其中subheader明确提示用户:"The latest version of Home Assistant is being downloaded. This may take 20 minutes or more."(正在下载最新版本,可能需要 20 分钟甚至更久)。

轮询节奏由常量控制(landing-page/src/ha-landing-page.ts):

常量值含义
ASSUME_CORE_START_SECONDS60假定 Core 正在启动的宽限秒数
SCHEDULE_CORE_CHECK_SECONDS1假定 Core 启动期间,每秒探测一次
SCHEDULE_FETCH_NETWORK_INFO_SECONDS5常规状态下每 5 秒刷新一次网络信息
SCHEDULE_FETCH_JOBS_INFO_SECONDS2每 2 秒刷新一次 Supervisor 任务进度

值得注意的是_checkCoreAvailability()(landing-page/src/ha-landing-page.ts)这个"核心就绪探测"逻辑:页面会尝试fetch("/manifest.json"),一旦请求成功,说明 Core 已经接管了服务,立即location.reload()触发页面刷新进入正式引导;若失败,则开启_coreCheckActive标志,进入 60 秒的密集探测窗口,并在窗口结束后自动关闭。这套机制保证了"下载完成 → 页面自动切换"的无缝体验。

2. 显示 / 隐藏 Supervisor 日志(Show / hide supervisor logs)

日志面板由 landing-page/src/components/landing-page-logs.ts 实现,其工作方式值得展开:

  • 默认通过getSupervisorLogsFollow()拉取/supervisor-api/supervisor/logs/follow?lines=500的流式接口(见 landing-page/src/data/supervisor.ts),用ReadableStream的 reader 持续读取,配合TextDecoder逐块解码,实现接近实时的日志滚动;
  • 日志内容通过ha-ansi-to-html组件做 ANSI 颜色转换与高亮;
  • 每次解析日志时用正则/^[\d\s-:]+(ERROR|CRITICAL)(.*)/gm检测错误级别行,一旦命中就触发landing-page-error事件并自动展开日志面板——这正是"安装出错时自动展示日志"的实现基础;
  • 若 Supervisor 日志流不可用(例如 Supervisor 自身还没起来),会回退到/observer/logs拉取 observer 日志,并且每 5 秒检查一次 Supervisor 日志是否恢复,恢复则切回流式模式;
  • 日志面板支持下载:点击下载按钮会以observer_${时间戳}.log为文件名下载完整日志(时间戳中的冒号会被替换为-,避免文件名非法)。

此外,日志面板还实现了"滚动到底部"交互细节:通过IntersectionController监听底部标记元素的可见性,用户未处于底部且出现新日志时,会显示"New logs - Click to scroll"悬浮按钮;自动滚动到日志末尾时该指示自动消失。

3. 外部链接(Links)

页脚提供三个对外入口:Read our Vision(阅读我们的愿景)、Join our community(加入社区)、Download our app(下载我们的 App)。这些入口直接复用了正式 onboarding 流程中的onboarding-welcome-links组件(见 landing-page/src/ha-landing-page.ts),因此文案与正式引导页保持完全一致,翻译均指向 src/translations/en.json 中ui.panel.page-onboarding.welcome下的共享键。

组件还通过extractSearchParam("redirect_uri") === "homeassistant://auth-callback"判断当前是否来自移动端 App 的授权回调(见 landing-page/src/ha-landing-page.ts),据此调整移动端链接的展示策略,实现"Web 浏览器与 App 场景差异化引导"。

4. DNS 问题处理器(DNS issue handler)

当 Supervisor 无法连接互联网时,页面需要引导用户自助修复。核心判定逻辑在 landing-page/src/ha-landing-page.ts:只要_networkInfo.host_internet为false,就渲染landing-page-network子组件;_networkInfoError为真时同样渲染(但展示的是"无法获取网络信息"的报错样式)。

landing-page-network组件(landing-page/src/components/landing-page-network.ts)的处理流程:

  1. 从网络信息中筛选出primary && enabled的主网络接口,汇总其 IPv4 与 IPv6 的 nameserver 并展示在告警文案中;
  2. 若找不到主接口,则提示用户"无法检测到主网络接口,因此无法修改 DNS",并禁用修复按钮;
  3. 提供两组备选 DNS 一键切换(定义于 landing-page/src/data/supervisor.ts):
方案IPv4IPv6
Cloudflare DNS1.1.1.1/1.0.0.12606:4700:4700::1111/2606:4700:4700::1001
Google DNS8.8.8.8/8.8.4.42001:4860:4860::8888/2001:4860:4860::8844
  1. 点击后调用setSupervisorNetworkDns(),即向/supervisor-api/network/interface/{主接口}/update发送POST请求,同时设置 IPv4/IPv6 的method: "auto"与对应 nameserver(见 landing-page/src/data/supervisor.ts);
  2. 成功后触发dns-set事件,通知主页面立即重新拉取网络信息;失败则弹出showAlertDialog告警对话框,提示查看日志后重试。

5. 错误处理器(Error handler)

当安装过程出现问题时,页面的处理方式与日志面板联动:

  • Supervisor 日志流中出现ERROR/CRITICAL行时,landing-page-logs触发landing-page-error事件,主组件据此把_supervisorError置为true;
  • 此时卡片主体会切换渲染一个ha-alert(alert-type 为error),标题为 "Error installing Home Assistant",描述为"安装出错,请查看日志获取更多信息"(对应 src/translations/en.json),同时日志面板保持展开,让用户能直接看到报错现场。

三、页面基础架构与源码级细节

组件树与生命周期

ha-landing-page(landing-page/src/ha-landing-page.ts)继承自LandingPageBaseElement(landing-page/src/landing-page-base-element.ts),后者又混入了themesMixin与ProvideHassLitMixin,使得这个未登录场景的页面也能复用前端的主题与语言基础设施。

firstUpdated阶段做了三件事(见 landing-page/src/ha-landing-page.ts):

  1. makeDialogManager(this)注册对话框管理器,供 DNS 失败时的告警对话框使用;
  2. 窗口宽度大于 450px 时动态加载particles粒子背景资源(移动端窄屏不加载以节省带宽);
  3. 立即发起 Supervisor 网络信息与任务信息的首次拉取,并进入各自的轮询循环。

国际化与语言切换

由于 Landing Page 出现在登录之前,它不能依赖用户配置,因此直接读取浏览器语言:

  • LandingPageBaseElement用getLocalLanguage()初始化language,通过getTranslation(null, language)拉取对应语言的翻译资源,再用computeLocalize生成localize函数;
  • 页脚内置ha-language-picker语言选择器,切换后通过_languageChanged写入localStorage的selectedLanguage键,实现语言记忆;
  • 同时依据translationMetadata判断该语言是否为 RTL(如阿拉伯语、希伯来语),自动应用computeDirectionStyles适配从右到左的排版。

对前端共享能力的复用

整个 Landing Page 大量复用正式前端的既有资产,这是它能在极小代码量下保持高质量 UI 的关键:ha-card、ha-progress-bar、ha-alert、ha-button、ha-spinner、ha-language-picker等组件,以及haStyle和onBoardingStyles样式集合,全部来自src/components、src/resources、src/onboarding等共享模块。可以说,Landing Page 是"以前端仓库为底座、叠加少量过渡页专属逻辑"的典型实现。

四、本地开发环境搭建(原文档实操指南)

原文档给出的开发方案是"双仓库协作":frontend 仓库负责构建前端资源,独立的 landingpage 仓库负责托管服务并把请求代理到 frontend 的开发服务器。整体思路与核心前端开发流程一致。

步骤一:配置 landingpage 开发服务器

  1. 克隆home-assistant/landingpage仓库;
  2. 在它的 devcontainer 配置中,把本 frontend 仓库以 bind mount 方式挂载进去,例如:
"mounts": ["source=/path/to/hass/frontend,target=/workspaces/frontend,type=bind,consistency=cached"]

原文档特别提醒:不要提交这个 mount 改动。首次构建 devcontainer 后即可移除,因为只要不重建容器,构建产物会保留这些选项。

  1. 使用 dev container 进入开发环境;
  2. 启动开发服务器时可配置以下可选环境变量:
环境变量作用示例
SUPERVISOR_HOST使用真实 Supervisor 数据时填写 Supervisor 的地址(需先按官方文档开启 Supervisor 远程 API 访问)SUPERVISOR_HOST=192.168.0.20:8888
SUPERVISOR_TOKEN从 Remote API proxy 加载项日志中获取的 Supervisor API 令牌SUPERVISOR_TOKEN=abc123
FRONTEND_PATH容器内 frontend 仓库的路径FRONTEND_PATH=/workspaces/frontend

三者组合的完整启动命令示例:

SUPERVISOR_TOKEN=abc123 SUPERVISOR_HOST=192.168.0.20:8888 FRONTEND_PATH=/workspaces/frontend go run main.go http.go mdns.go

原文档同时提示:这些变量也可以写进 devcontainer 设置,但那样灵活性较差——当你想临时切换测试不同的目标环境时,命令行方式随时可改。

步骤二:启动 frontend 开发服务器

在前端仓库一侧,完成依赖安装后,只需运行仓库内现成的脚本:

landing-page/script/develop

该脚本(landing-page/script/develop)实际执行的是./node_modules/.bin/gulp develop-landing-page。这个 gulp 任务(定义于 build-scripts/gulp/landing-page.js)依次完成:

  1. 设置NODE_ENV=development;
  2. 清理landing-page的旧构建产物(见 build-scripts/gulp/clean.js 中的clean-landing-page);
  3. 构建 landing-page 专属翻译(build-landing-page-translations),该翻译切分逻辑位于 build-scripts/gulp/translations.js,专门把顶层landing-page键提取出来,并确保base翻译中剔除 landing-page 部分以免重复打包;
  4. 拷贝翻译与静态资源(copy-translations-landing-page、copy-static-landing-page,见 build-scripts/gulp/gather-static.js),同时拷贝字体与 locale 数据;
  5. 生成开发用 HTML 页面(gen-pages-landing-page-dev);
  6. 启动 rspack 的 watch 模式持续编译(rspack-watch-landing-page)。

这样,landingpage 开发服务器就能通过FRONTEND_PATH找到本仓库,为过渡页提供实时的前端资源与热更新。

五、生产构建与产物

生产构建通过 landing-page/script/build_landing_page 触发,内部执行gulp build-landing-page(build-scripts/gulp/landing-page.js)。与开发任务相比,它设置NODE_ENV=production,并用rspack-prod-landing-page做一次性的生产打包,最后用gen-pages-landing-page-prod生成正式 HTML。

打包配置位于 build-scripts/bundle.cjs 的landingPage()方法:入口固定为landing-page/src/entrypoint.js,并标记isLandingPageBuild: true以启用专属的构建分支。产物输出路径由 build-scripts/paths.cjs 定义,主要落在landing-page/build/与landing-page/dist/下(含 latest 与带哈希的版本目录、静态资源目录),与正式前端走同一套outputPath/publicPath逻辑,便于 HAOS 集成部署。

六、结语

Landing Page 虽然只是一个过渡页面,但它是 HAOS 首次启动体验的第一道门面,承担着进度反馈、故障自愈与错误可视化三重职责。从本文可以看到,它的实现哲学非常清晰:尽可能复用前端仓库的既有组件与基础设施,只编写最少的过渡页专属逻辑——轮询 Supervisor 任务接口驱动进度条、流式读取并着色渲染日志、检测主网卡 DNS 并一键切换 Cloudflare/Google、探测 Core 就绪后自动刷新跳转。对于想为这套过渡页贡献功能或排查问题(例如网络检测、日志回退策略、移动端场景)的开发者,按照上文第四节的"双仓库 + devcontainer + 环境变量"流程即可快速拉起完整开发环境。

如需继续深入,推荐阅读以下源码入口:

  • 主组件与轮询逻辑:landing-page/src/ha-landing-page.ts
  • 日志流与错误检测:landing-page/src/components/landing-page-logs.ts
  • DNS 修复面板:landing-page/src/components/landing-page-network.ts
  • Supervisor / Observer 数据层:landing-page/src/data/supervisor.ts、landing-page/src/data/observer.ts
  • 国际化文案:src/translations/en.json
  • 构建任务与打包配置:build-scripts/gulp/landing-page.js、build-scripts/bundle.cjs
  • 前端
  • 智能家居
  • UI组件

【免费下载链接】frontend

:lollipop: Frontend for Home Assistant

项目地址:https://gitcode.com/gh_mirrors/frontend149/frontend
点击查看免费下载
上一篇:微信QQ防撤回三步上手:RevokeMsgPatcher从安装到原理一篇讲透
下一篇:被撤回的重要消息,还有救吗?Windows 开源防撤回工具 RevokeMsgPatcher 上手实测

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询