2.4 KiB
html/render-shell
(no submodules)
Purpose
Renders the GraphiQL HTML shell. The output embeds the configured GraphQL
endpoint, subscription endpoint, theme, and editor passthroughs into a
<script id="graphiql-config" type="application/json"> block — NOT inline
JavaScript — which the bundled graphiql.js parses at boot. This split
keeps script-src 'self' viable.
The shell is intentionally minimalist. The bundled bootstrap drives the explorer end-to-end (text area for the query, JSON pre for the response). Operators who want the full React-based GraphiQL distribution can swap out the asset payload on a fork.
Features
- Single-call render —
renderShell(options)returns the full document. - Defensive escaping — every caller-supplied string (default query, endpoints, theme, editor options blob) is HTML-escaped.
- No external host references — every
src/hrefpoints inside<uiEndpoint>/assets/. - Asset paths embed FNV-1a hashes for cache-busting.
Usage: Basic
import {
parseGraphiqlUiOptions,
renderShell,
} from "@suaveplan/api-graphql-ui-graphiql";
const html = renderShell(parseGraphiqlUiOptions({}));
// html starts with <!DOCTYPE html> and references /graphql/ui/assets/...
Usage: Advanced
import {
parseGraphiqlUiOptions,
renderShell,
} from "@suaveplan/api-graphql-ui-graphiql";
const html = renderShell(
parseGraphiqlUiOptions({
uiEndpoint: "/explorer",
graphqlEndpoint: "/api/v2/gql",
subscriptionEndpoint: "/api/v2/gql/ws",
theme: "dark",
defaultQuery: "{ viewer { id name } }",
editorOptions: { lineWrapping: true, tabSize: 2 },
})
);
API Reference
renderShell(options: GraphiqlUiOptions): string— produces the fully-substituted HTML document.escapeHtml(input: string): string— replaces&,<,>,", and'with HTML entities.
Implementation Notes
The config block uses application/json so the bootstrap can call
JSON.parse(node.textContent) without sniffing or eval. Escaping the
JSON via escapeHtml is technically over-protective (JSON inside a
<script type="application/json"> block doesn't need entity encoding
of </>/& for syntax correctness, but it does need it for
defense-in-depth when the JSON contains a </script> substring) — we
err on the safe side and run every embedded string through
escapeHtml.