svelte
svelte copied to clipboard
Preprocessing tries to process style string within script section
Describe the bug
I have a component which generates a small bit of HTML which is injected into an iframe
. The HTML contains a style
section which the preprocessing tries to transform, yielding a parser error because there are interpolated values in it.
(Accidentally opened this issue in svelte-preprocess
first: https://github.com/sveltejs/svelte-preprocess/issues/225
The problem is in the wrapper code though.)
To Reproduce
A component like this will cause the error:
<script>
function getItemHtml(html)
{
const style = window.getComputedStyle(document.documentElement);
const background = style.getPropertyValue('--background');
const foreground = style.getPropertyValue('--foreground');
return html + /*html*/`<style>
html
{
background: ${background};
color: ${foreground};
}
</style>`;
}
</script>
<style>
:global(:root)
{
--background: #333;
--foreground: #ddd;
}
</style>
<div>
HTML:
<pre>
{getItemHtml('Hello World')}
</pre>
</div>
[Repository with Webpack config]
Expected behavior No attempted transform and thus no errors.
Stacktraces
Stack trace
ERROR in ./src/app.svelte
Module build failed (from ./node_modules/svelte-loader/index.js):
CssSyntaxError: .\src\app.svelte:4:19: Unknown word
at Input.error (.\node_modules\postcss\lib\input.js:130:16)
at Parser.unknownWord (.\node_modules\postcss\lib\parser.js:563:22)
at Parser.other (.\node_modules\postcss\lib\parser.js:168:12)
at Parser.parse (.\node_modules\postcss\lib\parser.js:77:16)
at parse (.\node_modules\postcss\lib\parse.js:17:12)
at new LazyResult (.\node_modules\postcss\lib\lazy-result.js:60:16)
at Processor.<anonymous> (.\node_modules\postcss\lib\processor.js:138:12)
at Processor.process (.\node_modules\postcss\lib\processor.js:117:23)
at transformer (.\node_modules\svelte-preprocess\dist\transformers\globalStyle.js:55:67)
at Object.exports.runTransformer (.\node_modules\svelte-preprocess\dist\autoProcess.js:51:12)
at async style (.\node_modules\svelte-preprocess\dist\autoProcess.js:171:33)
at async .\node_modules\svelte\compiler.js:27016:32
at async Promise.all (index 0)
at async replace_async (.\node_modules\svelte\compiler.js:26971:52)
at async preprocess (.\node_modules\svelte\compiler.js:27012:19)
@ ./src/main.js 1:0-31 3:4-7
@ multi ./src/main.js
Information about your project:
- Your browser and the version: -
- Your operating system: Windows 10 64bit
-
svelte
version: 3.24.1 - Webpack
Severity
Low; workarounds exist.
Workaround
Trick the Regex looking for <style>
, e.g.:
return html + /*html*/`<${''}style>...</${''}style>`
Preprocessing happens before any parsing of the component, and is entirely regex based. I guess I'm ambivalent about how I think something like this ought to be handled. Do we want to start searching for a <script>
or a <style>
(whichever comes first), and then find its matching </script>
/</style>
and then start the search again after that closed tag for the next <script>
or <style>
?
I think I just ran into this obscure bug, here's the code:
<script type="text/typescript">
function renderUserStyles(suppliedPalette) {
if (!suppliedPalette)
return "";
let palette = "<style>:root {";
let paletteCount = 0;
suppliedPalette.map(color => {
palette += `--user-color-${paletteCount++}: ${color};`;
});
palette += "}</style>";
}
</script>
<!-- / stuff /-->
<svelte:head>
{@html renderUserStyles(thisUser.palette)}
</svelte:head>
The error I get is [!] (plugin svelte) CssSyntaxError: ~/project/src/pages/[username]/status/[slug].svelte:1:8: Unknown word
. Here is the error in full:
CssSyntaxError: ~/project/src/pages/[username]/status/[slug].svelte:1:8: Unknown word
at Input.error (~/project/node_modules/postcss/lib/input.js:82:16)
at Parser.unknownWord (~/project/node_modules/postcss/lib/parser.js:518:22)
at Parser.other (~/project/node_modules/postcss/lib/parser.js:149:12)
at Parser.parse (~/project/node_modules/postcss/lib/parser.js:59:16)
at parse (~/project/node_modules/postcss/lib/parse.js:11:12)
at new LazyResult (~/project/node_modules/postcss/lib/lazy-result.js:99:16)
at Processor.process (~/project/node_modules/postcss/lib/processor.js:33:12)
at transformer (~/project/node_modules/svelte-preprocess/dist/transformers/globalStyle.js:56:67)
at Object.exports.transform (~/project/node_modules/svelte-preprocess/dist/autoProcess.js:37:12)
at style (~/project/node_modules/svelte-preprocess/dist/autoProcess.js:161:33)
Spent the morning today trying to figure out what's going on here. As a note for other victims of this bug, you can work around it by fooling the regex:
const styles = `<${''}style>:root { ${css} }</${''}style>`;
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This came up again in https://github.com/sveltejs/kit/issues/1796 with the slight variation that style
was not nested in script
but rather contained within {@html ..}
.
An idea about how to approach this: First blank any script and style contents using the regex. Then try parsing the result with the Svelte parser. If that succeeds, pass on the results. If that fails, this means that the user uses markup preprocessors, too, at which point we can't do much more than falling back to the way it is now (purely regex based). This solution would be a little bit slower but more robust.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Had similar problems in prettier-plugin-svelte where I solved this by checking if a tag is inside another tag and remove the inner tag if so https://github.com/sveltejs/prettier-plugin-svelte/blob/master/src/lib/snipTagContent.ts
I created https://github.com/sveltejs/svelte-preprocess/issues/507 which seems to be a duplicate of this. Wanted to highlight that this bug even occurs if the <style>
string exists within a comment.
Here is another one in the same vein:
Discovered this with a string I was passing to highlight.js
Pasting svelte code into a template literal also causes some stuff to be added to the output string. I posted about it on Stackoverflow:
https://stackoverflow.com/questions/75223639/strange-error-with-template-literal-adding-to-string
Got this error after updating to sveltekit v2 with this component:
<script lang="ts">
import printCss from "$lib/styles/print.css?raw";
export let innerHtml: string;
const printContent = () => {
const printWindow = window.open("", "_blank");
if (printWindow) {
printWindow.document.write(
`<html><head><title>Print</title><style>${printCss}</style></head><body>`,
);
printWindow.document.write(innerHtml);
printWindow.document.write("</body></html>");
printWindow.document.close();
printWindow.onload = () => {
printWindow.print();
printWindow.onafterprint = () => {};
printWindow.close();
};
}
};
</script>
<button on:click={printContent}>
Print
</button>
@arggh 's solution worked to fix it.
I also ran into this after upgrading to sveltekit 2. Followed @arggh 's workaround.
Thanks @arggh still an issue for me. Is there an official solution?
I have run into this when inlining a styled SVG into my component, which doesn't seem to be an implausible use-case. The workaround doesn't work in my case because for some reason the style isn't added as a document node if I inject it using a function. Come to think of it I probably just needed an @html
here, but I've ended up taking a different approach.
I can have the style tag in my SVG, but I can't figure out how to pass it any parameters (so I can't change the fill or stroke colour, for example) without hitthing this error.