-
-
Notifications
You must be signed in to change notification settings - Fork 1
Description
Dear elliot, thanks for the nice library! I was very happy that you tought about nonce for the injected script, but I can't figure out how to use it. Can you provide an example?
The following example code obviously doesn't work as %sveltekit.nonce% is only available in app.html. And thinking about it, the nonce must not be available to the js context to remain secure.
<ThemeProvider scriptProps={{}} nonce="%sveltekit.nonce%">
{@render children?.()}
</ThemeProvider>Reading about it, I came by the following suggestion:
You can use a server hook with transformPageChunk to inject the partytown script into a script block in app.html that you have prepared with the nonce
<script nonce="%sveltekit.nonce%"> %partytown.snippet% </script>export const handle = (async ({ event, resolve }) => { return resolve(event, { transformPageChunk: ({ html }) => { return html.replace(%partytown.snippet%', partytownSnippet()); }, }); }) satisfies Handle;
Going down this road would require adapting head-script.svelte to export scriptBody. Or is there a better solution? Would it be better to just paste the script into app.html? This would require a way to disable the injection. What do you think? I would be happy to provide a PR.
Related:
In head-script.svelte you return early if !scriptProps thus the nonce doesn't get applied if no scriptProps are given.
svelte-themes/svelte-themes/src/lib/head-script.svelte
Lines 47 to 57 in 0b90e04
| let scriptAttributes = $derived.by(() => { | |
| if (!scriptProps) return ''; | |
| let str = ''; | |
| if (isServer() && nonce) { | |
| str += `nonce="${nonce}" `; | |
| } | |
| for (const [key, value] of Object.entries(scriptProps)) { | |
| str += `${key}="${value}" `; | |
| } | |
| return str; | |
| }); |
My svelte.config.js:
import adapter from '@sveltejs/adapter-node';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// https://svelte.dev/docs/kit/integrations
preprocess: vitePreprocess(),
kit: {
// https://svelte.dev/docs/kit/adapter-auto
adapter: adapter(),
// https://svelte.dev/docs/kit/configuration#csp
csp: {
directives: {
'default-src': ['self'],
'script-src': ['self'],
// 'unsafe-inline' is required for svelte-transition and bits-ui
'style-src': ['self', 'unsafe-inline'],
// data: is required for svgs used by tailwindcss
'img-src': ['self', 'data:'],
'connect-src': ['self'],
'font-src': ['self'],
'media-src': ['self'],
'form-action': ['self'],
'base-uri': ['self'],
'manifest-src': ['self'],
'worker-src': ['self'],
'frame-src': ['self'],
'object-src': ['self'],
},
},
},
};
export default config;