HTML Transformation

HTML transformation utilities for injecting scripts, metadata, and attributes into HTML documents.

Common use cases: - Inject CSRF tokens - Inject Inertia.js page props - Add data attributes to elements - Inject JSON data as global variables

HTML transformation and injection utilities for SPA output.

Regex patterns are compiled once at import time for performance.

litestar_vite.html_transform.inject_head_script(html: str, script: str, *, escape: bool = True, nonce: str | None = None) str[source]

Inject a script tag before the closing </head> tag.

Parameters:
  • html – The HTML document.

  • script – The JavaScript code to inject (without <script> tags).

  • escape – Whether to escape the script content. Default True.

  • nonce – Optional CSP nonce to add to the injected <script> tag.

Returns:

The HTML with the injected script. If </head> is not found, falls back to injecting before </html>. If neither is found, appends the script at the end. Returns the original HTML unchanged if script is empty.

Example

html = inject_head_script(html, “window.__DATA__ = {foo: 1};”)

litestar_vite.html_transform.inject_head_html(html: str, content: str) str[source]

Inject raw HTML into the <head> section.

This is used for Inertia SSR, where the SSR server returns an array of HTML strings (typically <title>, <meta>, etc.) that must be placed in the final HTML response.

Parameters:
  • html – The HTML document.

  • content – Raw HTML to inject. This is inserted as-is.

Returns:

The HTML with the content injected before </head> when present. Falls back to injecting before </html> or appending at the end.

litestar_vite.html_transform.inject_body_content(html: str, content: str, *, position: str = 'end') str[source]

Inject content into the body element.

Parameters:
  • html – The HTML document.

  • content – The content to inject (can include HTML tags).

  • position – Where to inject - “start” (after <body>) or “end” (before </body>).

Returns:

The HTML with the injected content. Returns the original HTML unchanged if content is empty or if no <body> tag is found.

Example

html = inject_body_content(html, ‘<div id=”portal”></div>’, position=”end”)

litestar_vite.html_transform.set_data_attribute(html: str, selector: str, attr: str, value: str) str[source]

Set a data attribute on an element matching the selector.

This function supports simple ID selectors (#id) and element selectors (div). For complex selectors, consider using a proper HTML parser.

Parameters:
  • html – The HTML document.

  • selector – CSS-like selector (currently supports #id and element names).

  • attr – The attribute name (e.g., “data-page”).

  • value – The attribute value (will be HTML-escaped automatically).

Returns:

The HTML with the attribute set. If the attribute already exists, it is replaced. Returns the original HTML unchanged if selector or attr is empty, or if no matching element is found.

Note

Only the first matching element is modified. The value is automatically escaped to prevent XSS vulnerabilities.

Example

html = set_data_attribute(html, “#app”, “data-page”, ‘{“component”:”Home”}’)

litestar_vite.html_transform.set_element_inner_html(html: str, selector: str, content: str) str[source]

Replace the inner HTML of an element matching the selector.

Supports only simple ID selectors (#app). This is intentionally limited to avoid the overhead and edge cases of a full HTML parser.

Parameters:
  • html – The HTML document.

  • selector – The selector (only #id supported).

  • content – The raw HTML to set as the element’s innerHTML.

Returns:

Updated HTML. If no matching element is found, returns the original HTML.

litestar_vite.html_transform.inject_page_script(html: str, json_data: str, *, nonce: str | None = None, script_id: str = 'app_page') str[source]

Inject page data as a JSON script element before </body>.

This is an Inertia.js v2.3+ optimization that embeds page data in a <script type="application/json"> element instead of a data-page attribute. This provides ~37% payload reduction for large pages by avoiding HTML entity escaping.

The script element is inserted before </body> with: - type="application/json" (non-executable, just data) - id="app_page" (Inertia’s expected ID for useScriptElementForInitialPage) - Optional nonce for CSP compliance

Parameters:
  • html – The HTML document.

  • json_data – Pre-serialized JSON string (page props).

  • nonce – Optional CSP nonce to add to the script element.

  • script_id – The script element ID (default “app_page” per Inertia protocol).

Returns:

The HTML with the script element injected before </body>. Falls back to appending at the end if no </body> tag is found.

Note

The JSON content is escaped to prevent XSS via </script> injection. Sequences like </ are replaced with <\\/ (escaped forward slash) which is valid JSON and prevents HTML parser issues.

Example

html = inject_page_script(html, ‘{“component”:”Home”,”props”:{}}’)

litestar_vite.html_transform.inject_json_script(html: str, var_name: str, data: dict[str, Any], *, nonce: str | None = None) str[source]

Inject a script that sets a global JavaScript variable to JSON data.

This is a convenience function for injecting structured data into the page. The data is serialized with compact JSON (no extra whitespace) and non-ASCII characters are preserved.

Parameters:
  • html – The HTML document.

  • var_name – The global variable name (e.g., “__LITESTAR_ROUTES__”).

  • data – The data to serialize as JSON.

  • nonce – Optional CSP nonce to add to the injected <script> tag.

Returns:

The HTML with the injected script in the <head> section. Falls back to injecting before </html> or at the end if no </head> is found.

Note

The script content is NOT escaped to preserve valid JSON. Ensure that data does not contain user-controlled content that could include malicious </script> sequences.

Example

html = inject_json_script(html, “__ROUTES__”, {“home”: “/”, “about”: “/about”})

litestar_vite.html_transform.inject_vite_dev_scripts(html: str, vite_url: str, *, asset_url: str = '/static/', is_react: bool = False, csp_nonce: str | None = None, resource_dir: str | None = None) str[source]

Inject Vite dev server scripts for HMR support.

This function injects the necessary scripts for Vite’s Hot Module Replacement (HMR) to work when serving HTML from the backend (e.g., in hybrid/Inertia mode). The scripts are injected into the <head> section.

For React apps, a preamble script is injected before the Vite client to enable React Fast Refresh.

Scripts are injected as relative URLs using the asset_url prefix. This routes them through Litestar’s proxy middleware, which forwards to Vite with the correct base path handling.

When resource_dir is provided, entry point script URLs are also transformed to include the asset URL prefix (e.g., /resources/main.tsx becomes /static/resources/main.tsx).

Parameters:
  • html – The HTML document.

  • vite_url – The Vite dev server URL (kept for backward compatibility, unused).

  • asset_url – The asset URL prefix (e.g., “/static/”). Scripts are served at {asset_url}@vite/client etc.

  • is_react – Whether to inject the React Fast Refresh preamble.

  • csp_nonce – Optional CSP nonce to add to injected <script> tags.

  • resource_dir – Optional resource directory name (e.g., “resources”, “src”). When provided, script sources starting with /{resource_dir}/ are prefixed with asset_url.

Returns:

The HTML with Vite dev scripts injected. Scripts are inserted before </head> when present, otherwise before </html> or at the end.

Example

html = inject_vite_dev_scripts(html, “”, asset_url=”/static/”, is_react=True)

litestar_vite.html_transform.transform_asset_urls(html: str, manifest: dict[str, Any], asset_url: str = '/static/', base_url: str | None = None) str[source]

Transform asset URLs in HTML based on Vite manifest.

This function replaces source asset paths (e.g., /resources/main.tsx) with their hashed production equivalents from the Vite manifest (e.g., /static/assets/main-C-_c4FS5.js).

This is essential for production mode when using Vite’s library mode (input: [“resources/main.tsx”]) where Vite doesn’t transform index.html.

Parameters:
  • html – The HTML document to transform.

  • manifest – The Vite manifest dictionary mapping source paths to output. Each entry should have a file key with the hashed output path.

  • asset_url – Base URL for assets (default “/static/”).

  • base_url – Optional CDN base URL override for production assets. When provided, takes precedence over asset_url.

Returns:

The HTML with transformed asset URLs. Returns the original HTML unchanged if manifest is empty. Asset paths not found in the manifest are left unchanged (no error is raised).

Note

This function transforms <script src="..."> and <link href="..."> attributes. Leading slashes in source paths are normalized for manifest lookup (e.g., “/resources/main.tsx” matches “resources/main.tsx” in manifest).

Example

manifest = {“resources/main.tsx”: {“file”: “assets/main-abc123.js”}} html = ‘<script type=”module” src=”/resources/main.tsx”></script>’ result = transform_asset_urls(html, manifest) # Result: ‘<script type=”module” src=”/static/assets/main-abc123.js”></script>’