Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

Start mode: generated entries render without the CSP nonce, and there is no per-request seam to supply one

未关闭
#388 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 1 天内回复

@everton-dgn 已经在做这个了。

开始于 2026年9月30日。

  • #389 来自 @everton-dgn —— 未关闭

评估

难度
5/5
预计耗时
一周以上
新手友好度
35/100
Issue 类型
功能
描述清晰度
描述清楚
活跃度
活跃
技术栈
typescript

调研方向

Start in src/ssr/index.ts at the generated-entry sites around lines 932 and 1394, then inspect the nonce handling near line 1279 and the Fetchable around line 1461. Reproduce the issue in examples/start-ssr with the two handleRequest calls; done means generated and authored entries propagate resolved nonce values, dev-injected tags are covered, and the object CSPNonce form no longer throws.

由索引模型根据 Issue 内容生成。

描述

Problem

A strict CSP (script-src 'nonce-…' 'strict-dynamic', no 'unsafe-inline') cannot be served with Start mode's generated entries. The only nonce input is handleRequest(request, { nonce }), added in #311, and it only reaches two tags: the injected client-entry <script> and the post-flush redirect fallback.

The generated entry renders with a fixed { manifest } and ignores the context it receives:

https://github.com/solidjs/solid-vite-plugin/blob/e4cdee454dbe0a99d9cb566d1dba72a93a9dcac1/src/ssr/index.ts#L932

https://github.com/solidjs/solid-vite-plugin/blob/e4cdee454dbe0a99d9cb566d1dba72a93a9dcac1/src/ssr/index.ts#L1394

So even when a host passes nonce, renderToStream never gets it. The hydration bootstrap (_$HY), the streamed data and swap scripts and the modulepreload links all go out without a nonce, and the page does not hydrate under the policy.

There is also no way to supply the nonce from inside the app:

  • Deployments that dispatch through the default Fetchable (Nitro calls mod.fetch(req)) never pass options. That is intentional, since the second argument of a Fetchable belongs to the host: https://github.com/solidjs/solid-vite-plugin/blob/e4cdee454dbe0a99d9cb566d1dba72a93a9dcac1/src/ssr/index.ts#L1461
  • start.middleware is the natural place to generate the nonce and set the Content-Security-Policy header, but it only sees (request, next). The options bag is fixed before the chain runs.
  • start.setup returns a component and start.renderMode returns a mode, so neither can change the stream options.
  • @solidjs/web only reads the nonce from the renderToStream options, not from the request event or locals.

Today the workaround is hand-written entry-server / entry-client files that pass nonce to renderToStream. Entries come in pairs, so both have to be written, and authored entries also give up the generated DefaultErrorBoundary. SolidStart had a per-request seam for this (createHandler(fn, (event) => ({ nonce })), see solidjs/solid-start#2252). #311 ported the client-entry part of that change.

A related bug: the object form CSPNonce that @solidjs/web accepts ({ script, style }) throws in the client-entry transform, because it escapes the value as a string:

https://github.com/solidjs/solid-vite-plugin/blob/e4cdee454dbe0a99d9cb566d1dba72a93a9dcac1/src/ssr/index.ts#L1279

TypeError: value.replace is not a function
Reproduction

With @solidjs/vite-plugin 3.0.0-next.47 and @solidjs/web 2.0.0-rc.13, in examples/start-ssr:

const html = await (await handleRequest(new Request('http://localhost/'), { nonce: 'abc' })).text();
// only the client-entry <script> carries nonce="abc";
// the _$HY bootstrap, the data scripts and the modulepreload links do not

await handleRequest(new Request('http://localhost/'), { nonce: { script: 'abc', style: false } });
// TypeError: value.replace is not a function
Proposal

A start.nonce option that follows the renderMode module convention. The option names a module that default-exports (event) => CSPNonce | undefined | Promise<…>. The handler resolves it after the middleware chain, next to resolveRenderMode, so a middleware can generate the nonce, set the header and store it on event.locals:

solid({ start: { middleware: './src/middleware.ts', nonce: './src/nonce.ts' }, ssr: true });

// src/nonce.ts
export default (event: RequestEvent) => event.locals.nonce as string | undefined;

The resolved value (or handleRequest's nonce, which keeps precedence) would go to:

  • the generated entry's renderToStream;
  • the client-entry tag and createSSRResponse, both through scriptNonce, which also fixes the object form;
  • in dev, the head tags the handler injects (the style patch and Vite client scripts, the collected styles, and a csp-nonce meta for the styles the Vite client injects);
  • authored entries, as context.nonce.

I have a PR ready and will link it here.

主要语言
TypeScript
星标
522
派生
72
平均合并
20 小时 1 分钟
30 天内合并 PR
31

环境准备

  • 没有 Dockerfile 或 Docker Compose 文件
  • 没有 Pull Request 模板
  • 阅读贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

solidjs/solid-vite-plugin 的其他 Issue

查看 solidjs/solid-vite-plugin 的全部 Issue

相似的 Issue

更多 TypeScript Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。