
Scalar Client-Side Rendering 实战用 CDN 零依赖渲染 API Reference 静态 HTML【免费下载链接】scalarScalar is an open-source API platform: Modern REST API Client Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar本文围绕 Scalar 开源仓库中packages/client-side-rendering包展开讲解如何通过renderApiReference一行调用把 OpenAPI/AsyncAPI 规范渲染成可直接下发的静态 HTML 页面。全文覆盖安装、API 签名、ESM/UMD 双 bundle 选择、CSP nonce 安全策略、函数型配置的序列化原理并结合仓库源码与测试用例给出可复现的实战依据。读完你将能在任意后端框架或静态站点中快速接入 Scalar API Reference且不引入任何服务端渲染依赖。什么是 Client-Side Rendering 包scalar/client-side-rendering是 Scalar 仓库中负责客户端渲染的最小封装包。它的核心思想是在服务端只生成一段携带配置的 HTML 字符串真正的 API Reference 界面由浏览器加载 CDN 上的脚本后渲染出来。这一点在包源码的注释中写得很明确Render the Scalar API Reference as a complete HTML document using the CDN. Generates static HTML that loads the scalar/api-reference standalone bundle from a CDN and renders client-side. No server-side dependencies required.见 src/html-rendering.ts也就是说服务端不需要安装 Vue、不需要打包scalar/api-reference前端代码只需要返回一个完整的 HTML 文档即可。该包因此成为仓库内多个框架集成NestJS、Next.js、Fastify、Hono、Express、SvelteKit、Astro、Docusaurus、Starlight 等共用的底层渲染工具例如 NestJS 集成就在 integrations/nestjs/src/nestJSApiReference.ts 中直接调用renderApiReference生成响应 HTML。安装包通过 npm 分发包名为scalar/client-side-renderingnpm install scalar/client-side-rendering安装后需要 Node.js 22 及以上版本见 package.json 中的engines字段。该包为纯 ESM 模块生产依赖仅有scalar/schemas、scalar/types、scalar/validation三个工作区包见 package.json测试用例 test/few-dependencies.test.ts 专门断言了这一零额外运行时依赖的特性。基础用法一次调用生成完整 HTML核心入口是renderApiReference函数最简单的用法如下对应 README 中的示例import { renderApiReference } from scalar/client-side-rendering const html renderApiReference({ pageTitle: My API Reference, config: { url: https://registry.scalar.com/scalar/apis/galaxy?formatjson, }, })返回的html是一个完整的 HTML 文档字符串可直接作为 HTTP 响应体返回或写入静态文件。函数完整签名如下见 src/html-rendering.tsrenderApiReference( options: { /** API Reference 配置类型为 AnyApiReferenceConfiguration */ config: AnyApiReferenceConfiguration /** 页面标题默认 Scalar API Reference */ pageTitle?: string /** CDN URL默认 jsDelivr */ cdn?: string /** CSP nonce用于严格 CSP 策略 */ nonce?: string /** 加载哪种构建产物ESM默认还是经典 UMD */ bundle?: string | boolean }, customTheme , ): string生成的 HTML 结构为标准的headbodyhead中包含title默认值为Scalar API Reference且pageTitle会经过 HTML 转义防止 XSS、meta charset、meta viewport以及按需生成的style标签body中只包含一个挂载点div idapp/div和一段初始化脚本见 src/html-rendering.ts。测试用例 src/html-rendering.test.ts 验证了默认输出包含!doctype html、titleScalar API Reference/title、script typemodule、div idapp/div以及createApiReference(#app等关键片段。配置合并与优先级renderApiReference内部会调用getConfiguration对配置做归一化处理见 src/html-rendering.ts若content是函数会先执行它把返回值作为实际内容若同时提供了content和urlurl优先content会被移除——因为从 URL 拉取规范时内联内容不再有意义。测试 src/html-rendering.test.ts 专门验证了这一行为。自定义主题与自定义 CSSrenderApiReference的第二个参数customTheme用于注入自定义主题 CSS同时config.customCss也支持注入自定义样式。两者都会被拼进style typetext/css标签中见 src/html-rendering.tsconfig.customCss始终注入customTheme仅在config.theme未设置时注入——即显式设置了内置主题如theme: kepler时自定义主题会被跳过避免冲突。测试 src/html-rendering.test.ts 验证了设置了theme属性时不再注入customTheme这一规则。选择构建产物ESM 与 UMD生成 HTML 时脚本标签的加载方式决定了页面首屏性能与兼容性。scalar/client-side-rendering支持两种构建默认现代 code-split ESM 构建默认情况下生成的 HTML 通过script typemodule加载代码分割的 ESM 构建.../scalar/api-reference/esm.js。由于是代码分割的浏览器只会按需下载渲染当前页面所需的懒加载 chunk而不是整个单体 UMD 包因此更少的 JavaScript 会阻塞首次渲染。默认 ESM CDN 地址定义在源码常量中见 src/html-rendering.tsexport const DEFAULT_ESM_CDN https://cdn.jsdelivr.net/npm/scalar/api-reference/esm.js生成的脚本形如script typemodule import { createApiReference } from https://cdn.jsdelivr.net/npm/scalar/api-reference/esm.js createApiReference(#app, { ...config }) /scriptcreateApiReference支持两种调用签名只传配置或传入挂载元素/选择器加配置见 packages/types/src/api-reference/html-api.ts。经典 UMD 构建以下三种情况会回退到经典 UMD 构建通过script src加载使用window.Scalar全局对象显式传入cdnURL——例如用于固定某个特定版本的 UMD 构建显式传入bundle: false设置了nonce严格 nonce 型 CSP原因见下文 CSP 一节。UMD 默认 CDN 地址同样定义在源码中见 src/html-rendering.tsexport const DEFAULT_CDN https://cdn.jsdelivr.net/npm/scalar/api-reference生成的脚本形如script srchttps://cdn.jsdelivr.net/npm/scalar/api-reference/script script typetext/javascript Scalar.createApiReference(#app, { ...config }) /scriptbundle 参数的优先级规则bundle参数的完整语义见 src/html-rendering.ts 与类型定义 packages/types/src/api-reference/html-rendering-configuration.tsbundle取值效果不设置默认加载 ESM 构建若同时给了cdn或nonce则回退 UMDtrue强制加载默认 ESM 构建DEFAULT_ESM_CDN优先级最高https://.../esm.js加载指定的 ESM 构建 URLfalse强制回退到经典 UMD 构建bundle的优先级高于cdn和nonce回退。测试 src/html-rendering.test.ts 验证了同时传入 cdn 和 bundle: true 时使用 ESM 而非 cdn 指定的 UMD。另外需要注意由于各个框架集成会把未知的渲染选项展开合并进config对象因此bundle也可能出现在config内部。renderApiReference会从config中读取它同时确保它不会泄漏到序列化给客户端的配置里见 src/html-rendering.ts测试 src/html-rendering.test.ts 验证了这一行为。Content Security Policy 与 nonce对于安全要求较高的站点nonce参数让 API Reference 可以在严格的script-src策略下运行no unsafe-inline、no unsafe-eval。为什么设置 nonce 时默认回退 UMDESM 构建通过原生import加载懒加载 chunk而import请求无法携带 nonce。因此如果 CSP 策略是 strict-nonce 型未开启strict-dynamic或未白名单 CDN 域名ESM 的 chunk 请求会被 CSP 拦截。而单文件 UMD 构建只有一次script请求、没有后续请求可以安全地打上 nonce所以只要设置了nonce默认就自动使用 UMD 构建。如果你在 CSP 中启用了strict-dynamic或显式白名单了 CDN 主机可以传bundle: true强制切回 ESM 构建。nonce 的完整行为设置nonce后生成 HTML 的行为包括见 src/html-rendering.ts内联script标签、CDNscript src标签、style标签都会带上nonce...属性额外输出meta propertycsp-nonce content... /让独立 bundle 在运行时注入样式表时也能复用同一个 noncebundle 以useStrictCSP构建时会读取该 metanonce 会经过属性转义quot;等防止恶意 nonce 注入突破 HTML 属性边界——测试 src/html-rendering.test.ts 专门验证了这一点。一个重要的限制即使有了 noncestyle-src仍然需要unsafe-inline。原因是 API Reference 会在运行时渲染内联的style...属性而 CSP nonce 只能授权script、style、link元素无法授权内联属性。也就是说nonce 带来的收益是完全严格的script-src但样式策略仍需放宽。这一点在类型注释packages/types/src/api-reference/html-rendering-configuration.ts与 CHANGELOGCHANGELOG.md中均有明确说明。使用示例const html renderApiReference({ pageTitle: My API Reference, nonce: r4nd0m, // 需与你 script-src 指令中的 nonce-... 保持一致且每次请求重新生成 config: { url: /openapi.json }, })测试 src/html-rendering.test.ts 验证了 nonce 场景下 UMD 回退、nonce 属性注入以及csp-noncemeta 的输出。源码级原理配置如何序列化进 HTMLrenderApiReference生成的脚本中内嵌了序列化后的配置对象这里有几个值得注意的实现细节。serializeConfigToJs函数也能跨边界存活普通JSON.stringify会静默丢弃函数值而 API Reference 的许多配置项本身就是函数例如请求钩子onBeforeRequest、排序器tagsSorter/operationsSorter、事件回调onLoaded、onRequestSent等。serializeConfigToJs见 src/html-rendering.ts解决了这个问题普通属性照常JSON.stringify函数属性通过Function.prototype.toString()输出为字面量 JavaScript 源码即onBeforeRequest: ({ request }) {...}包含函数的数组如plugins也会逐项以源码形式序列化见 serializeArrayWithFunctions输出的是一个合法的对象字面量不会出现前导逗号等语法错误。测试 src/html-rendering.test.ts 覆盖了tagsSorter、onBeforeRequest、redirect、generateModelSlug等十余种函数配置的保留以及纯函数配置不产生非法前导逗号的场景L377-L398。需要注意一个使用限制函数必须是箭头函数或function表达式。对象方法简写如onBeforeRequest(request) {}无法序列化为合法的独立表达式见 src/html-rendering.ts 注释。getConfigurationcontent 与 url 的取舍如前文所述getConfiguration会执行函数形式的content并在同时给出url时移除content见 src/html-rendering.ts对应测试见 src/html-rendering.test.ts。安全转义renderApiReference对pageTitle和nonce做了双层防御escapeHtml转义、、escapeHtmlAttribute在 HTML 转义之外再编码双引号防止属性逃逸见 src/html-rendering.ts。测试 src/html-rendering.test.ts 验证了恶意标题scriptalert(xss)/script会被安全转义。在真实框架集成中的用法renderApiReference是仓库内多个官方框架集成的公共底层。以 NestJS 集成为例integrations/nestjs/src/nestJSApiReference.ts 的实现模式如下import { renderApiReference } from scalar/client-side-rendering export function apiReference(givenConfiguration: NestJSReferenceConfiguration) { const configuration { _integration: nestjs, ...givenConfiguration, } const content () { const { cdn, pageTitle, nonce, ...config } configuration return renderApiReference({ config, pageTitle, cdn, nonce }, customThemeCSS) } // 支持 Express 与 Fastify 两种适配器直接以 text/html 返回 if (givenConfiguration.withFastify) { return (_req: FastifyRequest, res: ServerResponse) { res.writeHead(200, { Content-Type: text/html }) res.write(content()) res.end() } } return (_req: Request, res: Response) { res.send(content()) } }可以看到renderApiReference的第二个参数被用于注入整套自定义主题 CSScustomThemeCSS包含明暗双模式的颜色变量且cdn、pageTitle、nonce等渲染选项从配置中剥离后单独传入config则原样交给 API Reference。仓库中同样直接依赖scalar/client-side-rendering的集成还包括 Next.jsintegrations/nextjs/src/ApiReference.ts、Fastifyintegrations/fastify/src/fastifyApiReference.ts、Expressintegrations/express/src/apiReference.ts、Honointegrations/hono/src/scalar.ts、SvelteKitintegrations/sveltekit/src/scalar-api-reference.ts、Astro 与 Docusaurus 等。无论你使用哪种服务端技术都可以借鉴这一模式剥离渲染选项、传入 config 与 customTheme把返回的 HTML 字符串交给响应管道。结合 Server-Side Rendering 包的取舍仓库中还有一个配套的packages/server-side-rendering包用于带水合hydration的服务端渲染场景。renderApiReference的源码注释对此做了明确区分见 src/html-rendering.tsFor server-side rendering with hydration, use the server module instead.选择建议纯 CDN 客户端渲染页面内容由浏览器端 JS 渲染服务端只返回静态 HTML 外壳。适合对首屏 SEO 要求不高、希望零服务端依赖快速接入的场景也正是本文介绍的方式服务端渲染 水合需要服务端完整渲染出 API 文档内容再交给浏览器接管适合对首屏内容、SEO 与无 JS 环境有强要求的场景此时应使用server-side-rendering包。小结scalar/client-side-rendering以极小的 API 面一个renderApiReference函数完成了配置 → 完整 HTML 文档的转换其设计要点可以总结为零服务端依赖只需要scalar/schemas、scalar/types、scalar/validation三个内部包生成过程不触碰任何前端框架默认 ESM、按需 UMD默认加载 code-split 的 ESM 构建以优化首屏cdn/bundle: false/nonce三种情形自动回退单文件 UMDbundle可显式强制选择严格 CSP 友好nonce参数同时作用于内联脚本、CDN 脚本、样式标签与csp-noncemeta代价仅是style-src仍需unsafe-inline函数配置不丢失serializeConfigToJs把函数序列化为字面量 JavaScript让onBeforeRequest、排序器、事件回调等跨过 HTML 边界存活安全默认标题、nonce 均做 HTML/属性转义url与content冲突时以url为准。如果你想深入验证或二次开发建议阅读 src/html-rendering.ts 与其配套测试 src/html-rendering.test.ts测试覆盖了所有分支行为是理解该包语义的最佳入口。【免费下载链接】scalarScalar is an open-source API platform: Modern REST API Client Beautiful API References ✨ 1st-Class OpenAPI/Swagger Support项目地址: https://gitcode.com/GitHub_Trending/sc/scalar创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考