Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preprocessing tries to process style string within script section #5292

Open
brunnerh opened this issue Aug 19, 2020 · 15 comments
Open

Preprocessing tries to process style string within script section #5292

brunnerh opened this issue Aug 19, 2020 · 15 comments
Labels
awaiting submitter needs a reproduction, or clarification feature request stale-bot

Comments

@brunnerh
Copy link
Member

brunnerh commented Aug 19, 2020

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: sveltejs/svelte-preprocess#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>`
@Conduitry
Copy link
Member

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>?

@Conduitry Conduitry added proposal awaiting submitter needs a reproduction, or clarification labels Sep 10, 2020
@NetOpWibby
Copy link

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)

@arggh
Copy link
Contributor

arggh commented Mar 1, 2021

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>`;

@stale
Copy link

stale bot commented Jun 26, 2021

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.

@dummdidumm
Copy link
Member

dummdidumm commented Jul 2, 2021

This came up again in sveltejs/kit#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.

@stale
Copy link

stale bot commented Dec 29, 2021

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.

@dummdidumm
Copy link
Member

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

@samijaber
Copy link

I created sveltejs/svelte-preprocess#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.

@danawoodman
Copy link
Contributor

danawoodman commented Sep 9, 2022

Here is another one in the same vein:

image

Discovered this with a string I was passing to highlight.js

@bennymi
Copy link
Contributor

bennymi commented Jan 24, 2023

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

@rossrobino
Copy link

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.

@williamoverton
Copy link

I also ran into this after upgrading to sveltekit 2. Followed @arggh 's workaround.

@andresgutgon
Copy link

Thanks @arggh still an issue for me. Is there an official solution?

@glenatron
Copy link

glenatron commented Mar 18, 2024

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.

@cch264
Copy link

cch264 commented Sep 27, 2024

This is also an issue for me. I use strings that contain style tags in multiple places in my code. This was working fine in before upgrading to @sveltejs/vite-plugin-svelte from @sveltejs/kit/vite. Kind of ridiculous that upgrading caused a regression like this. The regex trickery is a super hacky fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting submitter needs a reproduction, or clarification feature request stale-bot
Projects
None yet
Development

Successfully merging a pull request may close this issue.