From 6732a5f3dba2a75c7f4bcd5716ba231f811ce928 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Tue, 13 Oct 2026 06:29:30 +0000 Subject: [PATCH] fix(ssr): project the CSP nonce locally instead of importing scriptNonce/styleNonce Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_018LY7F9czoRqdMEvk2QwPr1 --- .changeset/nonce-local-projection.md | 5 +++++ src/ssr/index.ts | 16 ++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 .changeset/nonce-local-projection.md diff --git a/.changeset/nonce-local-projection.md b/.changeset/nonce-local-projection.md new file mode 100644 index 0000000..5d2248d --- /dev/null +++ b/.changeset/nonce-local-projection.md @@ -0,0 +1,5 @@ +--- +'@solidjs/vite-plugin': patch +--- + +The generated start-mode server handler no longer imports `scriptNonce`/`styleNonce` from `@solidjs/web`. It projects each destination of a `{ script, style }` nonce with a local helper instead. Those helpers are internal to `@solidjs/web` (solidjs/solid#4016), and its single-script surfaces now take the full `CSPNonce` themselves. The handler works with `@solidjs/web` versions both before and after that change. diff --git a/src/ssr/index.ts b/src/ssr/index.ts index fb9c38c..d4491c3 100644 --- a/src/ssr/index.ts +++ b/src/ssr/index.ts @@ -1154,7 +1154,7 @@ export function startServe( const composeServerFunctions = internal.serverFunctions; const lines = [ - `import { createRequestEvent, createSSRResponse, commitEventResponse, scriptNonce, styleNonce, isResponseEnvelope } from '@solidjs/web';`, + `import { createRequestEvent, createSSRResponse, commitEventResponse, isResponseEnvelope } from '@solidjs/web';`, ...(isBuild ? [`import { reportServerError } from 'solid-js/internal';`] : []), `import { provideRequestEvent } from ${JSON.stringify(STORAGE_SOURCE)};`, `import * as entry from ${JSON.stringify(entryServerSpec())};`, @@ -1326,12 +1326,20 @@ export function startServe( ` return value ? ' nonce="' + escapeAttribute(value) + '"' : '';`, `}`, ``, + // One destination of a `CSPNonce` (a string, or a `{ script, style }` + // pair with `false` for an un-nonced destination). Kept local: the + // matching @solidjs/web helpers are internal. + `function destinationNonce(nonce, destination) {`, + ` const value = typeof nonce === 'string' ? nonce : nonce && nonce[destination];`, + ` return typeof value === 'string' && value ? value : undefined;`, + `}`, + ``, // The client entry and the dev scripts take the script destination of // a `{ script, style }` pair; the dev styles and the csp-nonce meta the // style destination. `function createHtmlChunkTransform(clientEntry, extraHead, nonce) {`, - ` const nonceAttr = nonceAttribute(scriptNonce(nonce));`, - ` const styleAttr = nonceAttribute(styleNonce(nonce));`, + ` const nonceAttr = nonceAttribute(destinationNonce(nonce, 'script'));`, + ` const styleAttr = nonceAttribute(destinationNonce(nonce, 'style'));`, ` let first = true;`, ` let injected = false;`, ` return (chunk) => {`, @@ -1527,7 +1535,7 @@ export function startServe( // single-script surfaces. ` return createSSRResponse(result, event, {`, ` responseInit: options.responseInit,`, - ` nonce: scriptNonce(nonce) || null,`, + ` nonce: destinationNonce(nonce, 'script') || null,`, ` transformChunk: createHtmlChunkTransform(clientEntry, options.devHead, nonce),`, ` });`, `}`,