Describe the bug
SvelteKit's create_function_as_string in src/exports/vite/build/utils.js wraps CSS content into a JavaScript template literal, but uses JSON.stringify to escape the string contents. JSON.stringify does not escape backticks or ${ sequences, since those are not special in JSON strings — but they are special in template literals.
This causes a SyntaxError: Invalid or unexpected token during prerendering when any CSS content contains a literal backtick character.
Suggested fix
Escape backticks and ${ sequences after JSON.stringify:
export function create_function_as_string(name, placeholder_names, str) {
str = s(str).slice(1, -1).replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
const args = placeholder_names ? placeholder_names.join(', ') : '';
return `function ${name}(${args}) { return \`${str}\`; }`;
}
Severity
This is a build-breaking bug triggered by a common CSS library (@tailwindcss/typography) combined with inlineStyleThreshold. Standard Vite/PostCSS plugin hooks cannot work around it because build_server_nodes runs inside SvelteKit's own writeBundle hook, after all user plugin hooks have executed, and immediately before prerender.
Workaround
Using patch-package to apply the above one-line fix to src/exports/vite/build/utils.js.
Reproduction
- Create a SvelteKit project with
@tailwindcss/typography and an inlineStyleThreshold large enough to inline the full stylesheet:
// svelte.config.js
export default {
kit: {
adapter: adapter(),
inlineStyleThreshold: 150000,
},
};
- Include
@tailwindcss/typography in your CSS:
@import "tailwindcss";
@plugin '@tailwindcss/typography';
- Run
vite build
The build fails during SSR prerendering with:
SyntaxError: Invalid or unexpected token
Root cause
@tailwindcss/typography generates a CSS rule with a literal backtick:
.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before,
.prose :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after {
content: "`";
}
In create_function_as_string, the CSS is embedded into a template literal:
export function create_function_as_string(name, placeholder_names, str) {
str = s(str).slice(1, -1); // s = JSON.stringify
const args = placeholder_names ? placeholder_names.join(', ') : '';
return `function ${name}(${args}) { return \`${str}\`; }`;
}
JSON.stringify converts the CSS to a JSON string and strips the outer quotes, but backticks pass through unescaped. The resulting generated code in .svelte-kit/output/server/stylesheets/*.css.js looks like:
export default function css(assets, base) { return `...content:"\`"...`; }
// ^ breaks the template literal
Logs
System Info
- `@sveltejs/kit` 2.55.0
- `@tailwindcss/typography` (via `@tailwindcss/postcss`)
- Tailwind CSS v4.0.9
- Node.js v24
- Vite 6
Severity
serious, but I can work around it
Additional Information
AI assisted issue, but real issue impacting pretty popular SvelteKit template: https://github.com/scosman/CMSaasStarter
Describe the bug
SvelteKit's
create_function_as_stringinsrc/exports/vite/build/utils.jswraps CSS content into a JavaScript template literal, but usesJSON.stringifyto escape the string contents.JSON.stringifydoes not escape backticks or${sequences, since those are not special in JSON strings — but they are special in template literals.This causes a
SyntaxError: Invalid or unexpected tokenduring prerendering when any CSS content contains a literal backtick character.Suggested fix
Escape backticks and
${sequences afterJSON.stringify:Severity
This is a build-breaking bug triggered by a common CSS library (
@tailwindcss/typography) combined withinlineStyleThreshold. Standard Vite/PostCSS plugin hooks cannot work around it becausebuild_server_nodesruns inside SvelteKit's ownwriteBundlehook, after all user plugin hooks have executed, and immediately beforeprerender.Workaround
Using
patch-packageto apply the above one-line fix tosrc/exports/vite/build/utils.js.Reproduction
@tailwindcss/typographyand aninlineStyleThresholdlarge enough to inline the full stylesheet:@tailwindcss/typographyin your CSS:vite buildThe build fails during SSR prerendering with:
Root cause
@tailwindcss/typographygenerates a CSS rule with a literal backtick:In
create_function_as_string, the CSS is embedded into a template literal:JSON.stringifyconverts the CSS to a JSON string and strips the outer quotes, but backticks pass through unescaped. The resulting generated code in.svelte-kit/output/server/stylesheets/*.css.jslooks like:Logs
System Info
Severity
serious, but I can work around it
Additional Information
AI assisted issue, but real issue impacting pretty popular SvelteKit template: https://github.com/scosman/CMSaasStarter