Summary
When a template contains a plain <style> element before a <style scoped> one, the scoped block's CSS is silently discarded: no stylesheet is emitted for it, no classes are collected from it, and no error or warning is produced.
Cause
src/build/template-plugin.js:119 selects the style element to extract by tag alone, ignoring attributes:
let styleTag = node.body.find(
(n) => n.type === 'ElementNode' && n.tag === 'style',
);
if (hasScopedAttribute(styleTag)) {
With a global <style> first, find returns that one, hasScopedAttribute is false, and the whole extraction branch is skipped -- so addInfo and request.inline.create never run for the scoped block. The ElementNode visitor then still matches the scoped element later in the traversal and returns null for it, removing it from the compiled template.
Net effect: the scoped CSS is deleted from the output and never emitted anywhere.
Reproduction
<template>
<style>
.global { color: red; }
</style>
<style scoped>
.scoped { color: blue; }
</style>
</template>
.scoped is dropped. Reversing the order of the two blocks makes it work.
The same applies to a second <style scoped> in one template: only the first style element is ever considered.
Suggested fix
Find the first scoped style element rather than the first style element:
let styleTag = node.body.find(
(n) => n.type === 'ElementNode' && n.tag === 'style' && hasScopedAttribute(n),
);
That leaves the existing "only at the root" and nested-block errors intact. If supporting more than one <style scoped> per template is out of scope, an explicit error for the second one would at least be louder than dropping it.
How this surfaced
Found while reviewing #422, which adds a stylelint customSyntax for inline blocks. That syntax lints every root-level <style scoped>, so it reports problems in CSS the build silently discards. Rather than teach the linter to replicate this behaviour, #422 documents the divergence and points here.
Summary
When a template contains a plain
<style>element before a<style scoped>one, the scoped block's CSS is silently discarded: no stylesheet is emitted for it, no classes are collected from it, and no error or warning is produced.Cause
src/build/template-plugin.js:119selects the style element to extract by tag alone, ignoring attributes:With a global
<style>first,findreturns that one,hasScopedAttributeis false, and the whole extraction branch is skipped -- soaddInfoandrequest.inline.createnever run for the scoped block. TheElementNodevisitor then still matches the scoped element later in the traversal and returnsnullfor it, removing it from the compiled template.Net effect: the scoped CSS is deleted from the output and never emitted anywhere.
Reproduction
.scopedis dropped. Reversing the order of the two blocks makes it work.The same applies to a second
<style scoped>in one template: only the first style element is ever considered.Suggested fix
Find the first scoped style element rather than the first style element:
That leaves the existing "only at the root" and nested-block errors intact. If supporting more than one
<style scoped>per template is out of scope, an explicit error for the second one would at least be louder than dropping it.How this surfaced
Found while reviewing #422, which adds a stylelint
customSyntaxfor inline blocks. That syntax lints every root-level<style scoped>, so it reports problems in CSS the build silently discards. Rather than teach the linter to replicate this behaviour, #422 documents the divergence and points here.