Homepage Widget 完全指南:Service 与 Info 两类 Widget 的配置与实现原理
2026/9/10 21:35:35 网站建设 项目流程

Homepage Widget 完全指南:Service 与 Info 两类 Widget 的配置与实现原理

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

Homepage 是一个高度可定制的首页 / 起始页 / 应用仪表盘,其核心亮点在于强大的 Widget(小部件)体系。本指南以 docs/widgets/index.md 为主干,系统讲解 Homepage 的两类 Widget——Service Widget(服务状态小部件)与 Info Widget(信息小部件)——的配置方法、挂载位置、常用参数,并结合仓库源码剖析其解析、渲染与高亮引擎的实现原理。读完本文,你将能在自己的services.yamlwidgets.yaml中熟练为任意服务挂载状态面板,在页面头部部署天气、时钟、资源监控等信息组件,并理解 Widget 从前端渲染到后端配置的完整链路。

概览:Homepage 的 Widget 体系

Homepage 将 Widget 划分为两种类型,分别对应两个配置文件:

类型用途配置文件渲染位置
Service Widget展示某个服务(通常是 Web 服务或 API)的运行状态与指标services.yaml服务卡片下方
Info Widget在页面头部展示系统或环境信息widgets.yaml页面顶部 Header 区域

这种划分从源码层面得到了印证:后端分别通过servicesFromConfig()解析services.yaml、通过widgetsFromConfig()解析widgets.yaml,两者均在 src/utils/config/service-helpers.js 与 src/utils/config/widget-helpers.js 中实现,且都先经过substituteEnvironmentVars()做环境变量替换,再交给yaml.load()解析。

Service Widget:为服务挂载状态面板

Service Widget 用于展示一个服务的运行状态,常见的例子包括 Plex、Sonarr、Uptime Kuma 等。它们定义在services.yaml中,作为某个服务条目的widget(单个)或widgets(多个)子项。以下是官方文档给出的完整示例:

- Plex: icon: plex.png href: https://plex.my.host description: Watch movies and TV shows. server: localhost container: plex widgets: - type: tautulli url: http://172.16.1.1:8181 key: aabbccddeeffgghhiijjkkllmmnnoo - type: uptimekuma url: http://172.16.1.2:8080 slug: aaaaaaabbbbb

在这个例子中,Plex服务自身通过href提供跳转链接,同时通过servercontainer关联了 Docker 容器(用于显示容器状态),并挂载了两个服务 Widget:tautulli(Plex 统计数据)与uptimekuma(Uptime Kuma 监控状态)。值得注意的是,服务 Widget 的类型并不强制要求与服务本身一致——官方文档明确说明"widget type often matching the service type, but that's not forced"。

关于 Service Widget 的完整配置细则(包括服务分组、嵌套分组、图标、ping、站点监控、Docker 集成等),请参考 Service 配置文档。下面从源码角度补充几个关键机制。

单个 Widget 与多个 Widget

服务条目下既可以使用单数形式的widget,也可以使用复数形式的widgets数组。从 service-helpers.js 的实现可以看出,解析阶段会将单数的widget统一转换为widgets数组:

if (!cleanedService.widgets) cleanedService.widgets = []; if (cleanedService.widget) { cleanedService.widgets.push(cleanedService.widget); delete cleanedService.widget; }

这意味着两种写法最终等价,你可以按需选择。需要注意:官方文档特别提示,通过 Kubernetes Ingress 注解方式定义的多个 Widget 暂不支持(Multiple widgets per service are not yet supported with Kubernetes ingress annotations)。

Widget 类型的注册与别名

Homepage 内置了超过 150 种服务 Widget。所有已注册的类型集中维护在 src/widgets/widgets.js 中,它是一个type -> widget 定义的映射表。从源码结构看,部分类型还提供了兼容别名,例如:

  • hoarder: karakeep(旧名 Hoarder 指向 Karakeep)
  • ical: calendar(iCal 指向日历组件)
  • jellyseerr: seerroverseerr: seerr(Jellyseerr / Overseerr 共用 Seerr 实现)
  • pialert: netalertx
  • unifi_console: unifi

前端渲染时,src/components/services/widget.jsx 会根据widget.typecomponents映射表(即 src/widgets/components.js)中取出对应的 React 组件;若类型未注册,则会渲染一个提示"missing type"的占位块,并用 ErrorBoundary 包裹避免整页崩溃。

自定义 HTTP 请求头

对于需要向反代或 API 网关发起请求的 Widget,可以附加headers传递额外请求头,这在"反向代理期望某个秘密请求头"的场景下非常有用:

- UptimeRobot: icon: uptimekuma.png href: https://uptimerobot.com/ widget: type: uptimerobot url: https://api.uptimerobot.com key: ${UPTIMEROBOT_API_KEY} headers: User-Agent: homepage X-Auth-Key: your-secret-here

注意这里key使用了${UPTIMEROBOT_API_KEY}环境变量占位符——所有配置文件都会先经过substituteEnvironmentVars()做变量替换,因此敏感信息可以安全地存放在环境变量中而不是明文写进 YAML。若通过 Docker Labels 或 Kubernetes 注解定义服务,则使用点号记法,例如homepage.widget.headers.X-Auth-Key=secretgethomepage.dev/widget.headers.X-Auth-Key: "secret"

字段可见性:fields

每个 Widget 都可以通过fields属性控制显示哪些指标字段,未指定时展示全部字段。fields必须是合法的 YAML 字符串数组:

- Sonarr: icon: sonarr.png href: http://sonarr.host.or.ip widget: type: sonarr fields: ["wanted", "queued"] url: http://sonarr.host.or.ip key: apikeyapikeyapikeyapikeyapikey

在所有情况下,即使不写fields属性,Widget 也能正常工作并展示所有字段。从 service-helpers.js 的实现看,fields既支持 YAML 数组,也支持 JSON 字符串(Docker Label 场景下常用),解析失败时会被降级为null并记录错误日志,不会导致崩溃。

指标高亮:highlight

Widget 支持基于规则的"块高亮"——根据指标数值或字符串自动给度量块着色(如队列积压量超过阈值变红)。将highlight配置段附加在 Widget 配置中,用字段名(如queuedlan_users)作为键,映射一组数值或字符串规则:

- Sonarr: icon: sonarr.png href: http://sonarr.host.or.ip widget: type: sonarr url: http://sonarr.host.or.ip key: ${SONARR_API_KEY} highlight: queued: numeric: - level: danger when: gte value: 20 - level: warn when: gte value: 5 - level: good when: eq value: 0 status: string: - level: danger when: regex value: "(failed|import) pending" - level: good when: equals value: "All good" status_code: string: - level: warn when: regex value: "^5\\d{2}$"

规则支持的运算符如下:

  • 数值运算符when):gtgteltlteeqnebetweenoutside
  • 字符串运算符equalsincludesstartsWithendsWithregex
  • 通用修饰:每条规则可用negate: true取反;字符串规则可传caseSensitive: true或自定义正则flagsbetween/outside配合min/max使用

此外还支持valueOnly: true,只对指标数值部分高亮、保留标签原本颜色:

- Sonarr: ... highlight: queued: valueOnly: true ...

高亮引擎的完整实现位于 src/utils/highlights.js,其中值得注意的细节包括:

  • 三个内置级别good/warn/danger对应一组 Tailwind 类(见DEFAULT_LEVEL_CLASSES),并可通过全局或 Widget 级levels覆盖;
  • 数值解析非常健壮(parseNumericValue):能处理"1,234"千分位、"1.5"小数、带单位后缀的字符串等,会尽量从格式化后的展示值中提取数字,但官方文档建议<Block>传入纯数字或纯字符串以获得最可靠的结果
  • 字段键支持widgetType.fieldName形式的命名空间化匹配,便于对同名指标做类型级规则隔离。

注意:官方文档明确指出custom api Widget 不支持 highlight

Info Widget:在页面头部展示系统信息

Info Widget 用于在首页顶部展示系统或环境信息。它们定义在widgets.yaml文件中,官方文档给出的基础示例是天气组件 Open-Meteo:

- openmeteo: label: Current latitude: 36.66 longitude: -117.51 cache: 5

Info Widget 的详细配置说明见 Info Widgets 配置文档,完整的可用组件列表见 Info Widgets 索引。目前内置的 Info Widget 包括:Date & Time、Glances、Greeting、Kubernetes、Logo、Longhorn、Open-Meteo、OpenWeatherMap、Resources、Search、Stocks、UniFi Controller 等。

Info Widget 的解析与安全处理

从 widget-helpers.js 的源码可以看到 Info Widget 的解析逻辑:widgetsFromConfig()读取widgets.yaml,将"便于书写的 YAML 对象"映射为"便于前端消费的 JS 数组",每个条目被规范化为{ type, options }结构,其中options里注入了一个自动生成的index字段用于区分同名 Widget:

const widgetsArray = widgets.map((group, index) => ({ type: Object.keys(group)[0], options: { index, ...group[Object.keys(group)[0]], }, }));

另一个值得关注的函数是cleanWidgetGroups():它在把配置下发给前端之前,会主动剥离敏感字段——usernamepasswordkeyapiKey一律删除;除searchglances之外的 Widget,其url也会被删除。这意味着 API 密钥等凭据永远不会出现在浏览器端。当需要凭据发起请求时,后端通过getPrivateWidgetOptions(type, widgetIndex)type + index精确取回私有选项,实现了前后端凭据隔离。

布局规则

Info Widget 按照在widgets.yaml中定义的顺序依次渲染,调整顺序只需移动文件中的条目即可。需要注意:部分 Widget(weather、search、datetime)会被对齐到屏幕右侧,这会直接影响整体布局,编排时需要一并考虑。

为 Info Widget 添加链接

Logo、文本等信息组件可以通过href选项变成可点击链接:

logo: href: https://example.com target: _blank # 可选,也可以在 settings 中全局设置

target默认在全局设置中定义,此处可针对单个 Widget 覆盖。

实例:Open-Meteo 天气组件

Open-Meteo 是官方推荐的天气组件,完全无需注册。它的完整配置项如下(取自 Open-Meteo 组件文档):

- openmeteo: label: Kyiv # 可选,显示在城市名位置 latitude: 50.449684 longitude: 30.525026 timezone: Europe/Kiev # 可选 units: metric # 或 imperial cache: 5 # API 响应的缓存分钟数,用于控制请求频率 format: # 可选,Intl.NumberFormat 选项 maximumFractionDigits: 1

关键参数说明:

  • latitude/longitude:坐标;两者均可省略,此时组件会使用浏览器定位(要求安全上下文,例如 HTTPS);
  • cache:以分钟为单位的 API 响应缓存时间,用于将请求频率控制在 Open-Meteo 的限额之内;
  • unitsmetricimperial
  • format:透传给Intl.NumberFormat的格式化选项,例如限制小数位。

端到端调用链:一次 Widget 渲染的全过程

综合以上源码,可以梳理出一条完整的调用链(从源码结构推断):

  1. 应用启动时,后端分别调用servicesFromConfig()(src/utils/config/service-helpers.js)与widgetsFromConfig()(src/utils/config/widget-helpers.js)读取services.yaml/widgets.yaml,并先做环境变量替换;
  2. parseServicesToGroups()将顶层数组递归解析为{ name, type, services, groups }的组树结构,支持无限层级的嵌套分组;解析失败的服务会被记录 warn 日志并跳过(service-helpers.js);
  3. cleanServiceGroups()对每个 Widget 做白名单清洗:只把fieldshideErrorshighlighttype以及各类型专属选项(如 docker 的server/container、glances 的chart/pointsLimit、iframe 的src等)透传给前端,并按类型做 JSON 解析与布尔化处理;
  4. 前端 widget.jsx 依据type从组件映射表中取出组件并渲染,未知类型落入service-missing占位提示。

这条链路保证了:配置的容错性(单个服务解析失败不影响整体)、安全性(敏感凭据不出服务端)与可扩展性(新增类型只需在 src/widgets/widgets.js 注册)。

实战示例:构建一个带状态面板的媒体服务区

将上述知识整合,一个典型的完整services.yaml配置如下(媒体栈 + 监控):

- Media: - Sonarr: icon: sonarr.png href: http://sonarr.host/ description: Series management widget: type: sonarr url: http://sonarr.host key: ${SONARR_API_KEY} highlight: queued: numeric: - level: danger when: gte value: 20 - level: good when: eq value: 0 - Plex: icon: plex.png href: http://plex.host/ description: Movies & TV Shows server: media-server container: plex widgets: - type: tautulli url: http://tautulli.host:8181 key: ${TAUTULLI_API_KEY} - type: uptimekuma url: http://uptimekuma.host:3001 slug: plex-status - Monitoring: - Uptime Robot: icon: uptimekuma.png href: https://uptimerobot.com/ widget: type: uptimerobot url: https://api.uptimerobot.com key: ${UPTIMEROBOT_API_KEY} headers: X-Auth-Key: ${UPTIMEROBOT_SECRET}

配套的widgets.yaml头部信息区:

- greeting: text_size: xl - logo: icon: /icons/my-logo.png - datetime: text_size: xl format: timeStyle: short dateStyle: short - openmeteo: label: Current latitude: 36.66 longitude: -117.51 units: metric cache: 5

结语

Widget 是 Homepage 最具价值的扩展点之一:Service Widget 让每个服务卡片都拥有实时的状态与指标面板,Info Widget 则把系统与环境信息聚合到页面头部。通过本文,你已掌握两类 Widget 的配置语法(services.yamlwidget/widgetswidgets.yaml的顶层数组)、进阶能力(fields字段裁剪、highlight规则高亮、headers自定义请求头、环境变量注入),以及背后的解析与安全机制(凭据剥离、类型注册、别名兼容)。若要继续深入,可以研读 src/utils/config/service-helpers.js 中每个类型的白名单选项、src/utils/highlights.js 的高亮求值逻辑,或参考 widgets 组件文档 与 info 组件文档 中具体类型的配置页,按需组合出属于你自己的首页仪表盘。

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

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

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

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

立即咨询