
Gatsby 自定义 html.js 完全指南掌控 SSR HTML 输出的每一个标签【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby在 Gatsby 中html.js是服务端渲染SSR阶段生成 HTML 文档骨架的核心 React 组件负责渲染head以及核心 Gatsby 应用之外的其他 HTML 部分。本文以 docs/docs/custom-html.md 为骨架结合仓库中packages/gatsby/cache-dir/下的默认实现与 SSR 渲染管线源码完整讲解如何复制、修改html.js向head与footer注入自定义 HTML、添加自定义脚本并阐明它与 Gatsby SSR API、Head API、Script API 的职责边界与推荐取舍帮助你安全地定制每个页面的静态 HTML 输出。Gatsby 为什么需要 html.jsGatsby 在构建时会为每个页面生成静态 HTML 文件。这个 HTML 文档并非由浏览器端组件树直接渲染而是由一个专门的 React 组件服务端渲染出head以及核心 Gatsby 应用之外的其他部分。这个组件就是html.js。默认情况下Gatsby 随自身附带了开箱即用的html.js绝大多数站点不需要任何修改即可正常工作。只有当你有特殊定制需求例如需要向每个页面的head或footer插入自定义 HTML时才需要将默认实现复制到你的源码树中并自行修改。需要特别强调的是自定义html.js是当gatsby-ssr.js中的相应 API 不可用时的变通workaround方案。Gatsby 官方建议优先考虑使用 onRenderBody 或 onPreRenderHTML 替代。此外在 Gatsby Theme 内部不支持自定义html.js——如果正在开发主题请改用上述 SSR API 方法。第一步复制默认 html.js自定义的第一步是把 Gatsby 内置的默认实现复制到项目的src目录cp .cache/default-html.js src/html.js复制完成后你就可以按需修改src/html.js的内容。这里有一个前提需要注意.cache目录是 Gatsby 构建时生成的缓存目录因此上述命令必须在站点根目录执行且通常需要先运行过一次gatsby develop或gatsby build确保.cache目录已经存在。仓库中这份默认实现的完整源码位于 packages/gatsby/cache-dir/default-html.js其核心结构如下export default function HTML(props) { return ( html {...props.htmlAttributes} head meta charSetutf-8 / meta httpEquivx-ua-compatible contentieedge / meta nameviewport contentwidthdevice-width, initial-scale1, shrink-to-fitno / {props.headComponents} /head body {...props.bodyAttributes} {props.preBodyComponents} div key{body} id___gatsby dangerouslySetInnerHTML{{ __html: props.body }} / {props.postBodyComponents} /body /html ) }这份文件同时通过propTypes声明了全部可用 props 的类型是理解html.js契约的最佳参考HTML.propTypes { htmlAttributes: PropTypes.object, headComponents: PropTypes.array, bodyAttributes: PropTypes.object, preBodyComponents: PropTypes.array, body: PropTypes.string, postBodyComponents: PropTypes.array, }必需的 props一个都不能少html.js组件会从 Gatsby 的 SSR 渲染管线接收若干 props。其中渲染进页面所必需的关键 props 不可省略包括headComponents渲染进head的组件数组如 meta 标签、样式、预加载资源等preBodyComponents渲染进body开头、位于应用容器之前的组件数组body核心 Gatsby 应用的 HTML 字符串以dangerouslySetInnerHTML方式注入postBodyComponents渲染进body末尾、位于应用容器之后的组件数组如各类脚本。如果你在自己的html.js中遗漏了上述任何一个 props 的渲染页面将无法正确组装。Gatsby 的 SSR 构建流程会在static-entry.js中为这些 props 填充真实数据在 packages/gatsby/cache-dir/static-entry.js 中可以看到headComponents会以meta namegenerator contentGatsby ${gatsbyVersion} /作为初始值随后通过setHeadComponents、setPreBodyComponents、setPostBodyComponents等函数不断累积插件与框架注入的组件最终在文件末尾将组装好的数组作为 props 传入Html组件完成渲染。向head插入自定义 HTML如果你需要在站点的每个页面head中插入自定义 HTML可以直接在src/html.js的head区域添加内容例如head meta charSetutf-8 / meta httpEquivx-ua-compatible contentieedge / meta nameviewport contentwidthdevice-width, initial-scale1, shrink-to-fitno / {props.headComponents} {/* 你的自定义 head 内容 */} /head重要限制你在html.js组件中渲染的任何内容在客户端都不会像其他 React 组件那样被激活made live。html.js只参与服务端静态渲染渲染出的产物是一次性的静态 HTML 字符串不具备客户端交互与响应式更新能力。如果你需要动态更新head建议改用 Gatsby 的 Head API它能在组件中声明式地管理title、meta、link等标签并在客户端与 SSR 两侧保持一致。一个值得了解的底层细节在最终渲染前Gatsby 会对headComponents执行一次重排将meta标签始终排到最前避免大型内联样式等元素把 meta 标签挤到后面而影响爬虫解析。该逻辑实现在 packages/gatsby/cache-dir/static-entry.js 的reorderHeadComponents函数中——这意味着即使你在html.js里手动调整 head 内元素的书写顺序构建时仍可能被这套规则重新排序。向footer插入自定义 HTML对于向每个页面底部footer 区域插入自定义 HTML 的需求html.js是官方推荐的首选方式。在默认实现中这一区域对应body内___gatsby容器之后的{props.postBodyComponents}body {...props.bodyAttributes} {props.preBodyComponents} div key{body} id___gatsby dangerouslySetInnerHTML{{ __html: this.props.body }} / {props.postBodyComponents} {/* 你的自定义 footer 内容例如额外的统计脚本、页脚组件等 */} /body如果你是在编写插件而非站点本身则不推荐直接修改html.js插件无法覆盖站点的 html.js而应使用 Gatsby SSR API 中的setPostBodyComponents来完成等价注入。从源码看postBodyComponents正是各插件通过 SSR API 注入内容的落点在 packages/gatsby/cache-dir/static-entry.js 中Gatsby 会把 polyfill 脚本与构建产物脚本script标签追加进postBodyComponents最终统一渲染到/body之前。目标容器修复 Target container is not a DOM element如果你在页面中看到如下报错Uncaught Error: _registerComponent(...): Target container is not a DOM element.这意味着你的html.js缺失了必需的目标容器target container。在你的body内部必须存在一个id为___gatsby的div且通过dangerouslySetInnerHTML注入this.props.bodydiv key{body} id___gatsby dangerouslySetInnerHTML{{ __html: this.props.body }} /这是 Gatsby 客户端应用挂载hydrate的锚点浏览器端 React 会以#___gatsby为容器重新接管渲染。如果这个 div 缺失、被改名或位置不正确客户端应用将找不到挂载点从而抛出上述错误。在修改html.js时务必保留这一容器及其key、id、dangerouslySetInnerHTML三个关键属性。添加自定义 JavaScript你还可以使用 React 的dangerouslySetInnerHTML属性向 HTML 文档中注入自定义 JavaScript。例如在head或body末尾加入内联脚本script dangerouslySetInnerHTML{{ __html: var name world; console.log(Hello name); , }} /注意dangerouslySetInnerHTML是 React 中用于注入原始 HTML 的机制它不会经过转义因此只应对可信的、你自己编写或可控的内容使用避免注入不可信的外部数据。同时Gatsby 官方明确建议更推荐使用 Gatsby 的 Script API 来加载和管理脚本。Script API 提供了更完善的加载策略如load、idle、off-main-thread等、错误处理与去重机制能更好地兼顾性能与安全。html.js内联脚本的方式仅适用于需要完全手控输出、且无法被上述 API 覆盖的极少数场景。替代方案为什么优先使用 SSR API 而非 html.js自定义html.js虽然直接、强大但它是最后手段。Gatsby 推荐的正规路径是按职责分层使用内置 API需求场景推荐方案说明向head注入 meta、link、title 等Gatsby Head API组件内声明式管理支持动态更新向head/body注入组件SSR 阶段onRenderBody提供setHeadComponents、setPreBodyComponents、setPostBodyComponents站点与插件均可用可组合、可覆盖在渲染后重新调整/替换 head 组件onPreRenderHTML提供getHeadComponents、replaceHeadComponents等在最终写出 HTML 前介入加载脚本资源Gatsby Script API提供完善的加载策略与去重需要完全手控整个 HTML 骨架自定义html.js最后手段Theme 中不支持从实现层面看SSR API 与html.js共享同一套组件收集机制在 packages/gatsby/cache-dir/static-entry.js 中构建流程会在渲染Html前调用apiRunner(onPreRenderHTML, ...)将getHeadComponents、replaceHeadComponents、getPreBodyComponents、replacePreBodyComponents、getPostBodyComponents、replacePostBodyComponents交给各插件的onPreRenderHTML钩子允许它们在 HTML 写出前对组件集合做最后调整而onRenderBody则通过setHeadComponents/setPreBodyComponents/setPostBodyComponents完成注入其完整签名与用法示例见 packages/gatsby/cache-dir/api-ssr-docs.js 与 docs/docs/reference/config-files/gatsby-ssr.md。一个典型的gatsby-ssr.js注入示例const React require(react) exports.onRenderBody ({ setHeadComponents, setPostBodyComponents }) { // 向 head 注入自定义 meta setHeadComponents([ meta keycustom-meta nametheme-color content#663399 /, ]) // 向 /body 之前注入自定义脚本 setPostBodyComponents([ script keycustom-script dangerouslySetInnerHTML{{ __html: console.log(hi) }} /, ]) }为什么不建议在 Theme 中自定义 html.jsGatsby Theme 的本质是可复用的插件组合而html.js是站点级的文件主题无法覆盖站点的html.js两者组合时会导致行为不可预期。因此官方明确主题内应使用onRenderBody/onPreRenderHTML等 API 方法而非自定义html.js。同样的逻辑也适用于插件作者——凡是需要向 HTML 注入内容的插件都应通过 SSR API 完成。总结自定义html.js是 Gatsby 赋予开发者的终极控制权通过复制packages/gatsby/cache-dir/default-html.js到src/html.js你可以精确掌控每个静态页面 HTML 的head与 footer 输出前提是严格遵守必需 props 契约headComponents、preBodyComponents、body、postBodyComponents并保留id___gatsby目标容器。但它同时是一把双刃剑渲染出的内容在客户端不会活起来且在 Theme 与插件场景下不可用。务实的做法是遵循 Gatsby 的能力分层——动态 head 交给 Head API、脚本加载交给 Script API、通用注入交给 SSR API仅在这三者无法覆盖的边界场景如完全手控 HTML 骨架、插入固定 footer 内容才诉诸html.js。【免费下载链接】gatsbyReact-based framework with performance, scalability, and security built in.项目地址: https://gitcode.com/gh_mirrors/ga/gatsby创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考