I have a strange issue occurring.
I'm using PostCSS Extend which allows you to extend the styles of other classes.
When there is another style block in the template Svelte returns an error. When there are no other style blocks in the template it works fine. I understand why would error without the plugin installed as it's not conventional CSS syntax, but it doesn't make sense in this scenario.
<div class="component"><slot/></div>
<div>
<style></style>
</div>
<style>
%color {
color: red;
}
.component {
@extend %color;
}
</style>
I noticed this issue when I was using svg icons which had some style blocks inside them.
The error I get is:
Selector is expected
7: <style>
8:
9: %color {
^
10: color: red;
11: }
(node:26131) UnhandledPromiseRejectionWarning: Error: Could not find chunk that owns index.html
at /Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/core.js:689:19
at Array.forEach (<anonymous>)
at extract_css (/Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/core.js:685:16)
at RollupResult.to_json (/Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/core.js:846:18)
at handle_result (/Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/chunk-c6ac1203.js:239:55)
at /Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/chunk-c6ac1203.js:321:17
at Watcher.<anonymous> (/Users/mindthetic/Sites/repos/site/node_modules/sapper/dist/core.js:980:37)
at Watcher.emit (events.js:182:13)
at /Users/mindthetic/Sites/repos/site/node_modules/rollup/dist/rollup.js:26406:19
(node:26131) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 4)
It certainly looks like Svelte is not getting the processed CSS, which seems to imply that another plugin is not doing its job or is configured incorrectly. What does your build process look like? Can you see the output of the PostCSS plugin and/or the input of Svelte?
Thanks for taking a look at my issue. I've removed everything from the project including all other plugins. I'm not familiar with how to show the output of the PostCSS plugin or what input to show from Svelte however I have put my build config in a gist for reference. I'm using Sapper. Happy to upload a repo if it helps.
https://gist.github.com/mindthetic/4a3a14effbede472487fea0e13ab2802
Interestingly if the second style block comes after the top level style block then there is no error.
UPDATE: the output from the plugin when it's working is:
.component {
color: red;
}
Not sure if that helps.
I'm guessing it's something like postcss only processing the first script tag in a block of html. If you could upload a repo that would help a lot. There are a number of places the issue could be (in Svelte's preprocess handling, in svelte-preprocess, in PostCSS as a whole, in that particular plugin, etc.).
I understand. No problem.
Svelte's native preprocess options currently only work for the _first_ <script> and <style> tags.
svelte-preprocess _could_ extract the other tags via a markup preprocessor, but that's not the case, so there's nothing in the setup allowing you to have more than one style tag, unfortunately.
That explains the issue. I can fix this then by having the main style tag before anything else, but wonder if at the least Svelte's native preprocessor could check for top level style tags only?
I wonder whether it really needs to have the one tag limit in the first place!
Could there be problems if it passed every style tag through preprocess and simply concatenated them all before continuing?
Huh, I did not realize that about Svelte's native preprocessor. I was just independently discovering that when I saw @mrkishi's first comment.
Concatenating all of the style tags is not what we want to do - the whole point of additional style tags (at the non-top-level) is that they'll just be inserted as regular html elements without Svelte messing with them. So I'm undecided about whether all (non-top-level) style blocks should be passed through the preprocessor (probably?), but if there's a top-level one it should definitely be run through it, whatever else there is in the component markup.
I haven't dug far enough to find out where exactly the exception is thrown if there are multiple top-level style or script tags. It might be nice if that ran before it even attempts to run those preprocessors.
Oh, hm. I'd forgotten that svelte.preprocess was implemented as an entirely separate function than compilation. So it doesn't make sure to do much or any validation of the component before proceeding with style/script preprocessing. I think it would make sense to just make those apply to all such tags, and then later during compilation is when the exceptions will be thrown if there are two top-level ones.
It would be hard to determine which were top-level during preprocessing anyway, when we haven't done any parsing yet, and are just using simple regexes.
There is a g flag on the regular expression used to match these tags but then we don't actually follow through and do all of the replacements, making me think the current behavior might be an oversight.
Got a version of this working locally. Thanks to an async version of String#replace I had lying around, the code also was able to get a bit simpler. Going to tidy up and submit a PR, but I might not get to unit tests tonight.
This should be fixed in Svelte v3 with the improved preprocessing handling - multiple script and style blocks will be processed, not just the first ones.
Closing this - as mentioned above, this is addressed in v3, where multiple script and style blocks are all run through preprocessors.
Is there any way to re-discuss about this issue?
v3 brings single pre-processing of each style corresponding to each Components.
However postcss-extend has for goal to allow you to regroup selectors from different locations into one place.
An repo that shows the problem: https://github.com/dievardump/svelte-postcss-extend
App.svelte has this code:
<script>
import Child from './Child.svelte';
</script>
<style lang="postcss">
@import '../css/boot.css';
h1 {
@extend %colorRed;
}
</style>
<h1>Hello World!</h1>
<Child />
Child.svelte
<style lang="postcss">
@import '../css/boot.css';
p {
@extend %colorRed;
}
</style>
<p>Child content</p>
and boot.css
%colorRed {
color: red;
}
The expected output css would be:
h1.svelte-14xq4cx,
p.svelte-1bjf6u {
color: red;
}
/*# sourceMappingURL=main.css.map */
The resulting css is :
h1.svelte-14xq4cx {
color: red;
}
p.svelte-1bjf6u {
color: red;
}
/*# sourceMappingURL=main.css.map */
Which breaks the goal of postcss-extend, repeating the content that it was supposed to help to only have in one place, regrouping selectors to it.
The best way to achieve this, would be to post-process the emitted css file in svelte's css() function, but svelte throws an error at @extend %colorRed; making this impossible.
A possible way would be to be able to tell svelte to ignore a line with a comment flag :
p {
/* svelte-ignore */
@extend %colorRed;
}
or something similar that wouldn't break what exists, but allow more flexibility for post processing without throwing an error at what it doesn't understand.
Here I show an example with postcss-extend, but I have the same problems with postcss-mixins and other plugins which require sharing state between imported files.
Most helpful comment
This should be fixed in Svelte v3 with the improved preprocessing handling - multiple script and style blocks will be processed, not just the first ones.