Skip to content

Support multiple <style> blocks per SFC (previously only the first was ever read) - #10

Merged
aldanedev-create merged 1 commit into
mainfrom
fix/vel-runtime-and-css
Aug 27, 2026
Merged

Support multiple <style> blocks per SFC (previously only the first was ever read)#10
aldanedev-create merged 1 commit into
mainfrom
fix/vel-runtime-and-css

Conversation

@aldanedev-create

Copy link
Copy Markdown
Owner

One commit that landed after the previous PR on this branch was already merged. See commit message for full details: a .vel file with more than one <style> block (e.g. one scoped + one global) silently dropped every block after the first, with no error or warning. Fixed with proper multi-block parsing and a shared scope id across all scoped blocks in the same file.

…s ever read)

Continued the @teloce/sfc audit. parseSFC only ever found the *first*
<style> block in a .vel file via parseBlock's single (non-repeated)
match - any additional <style> blocks were silently dropped with no
error or warning at all. Confirmed via a real compile: a file with a
`<style scoped>` block followed by a second plain `<style>` block only
ever produced CSS for the first; the second block's rules vanished
entirely. Multiple style blocks (e.g. one scoped + one global) are a
real, common SFC pattern, so this is a genuine feature gap rather than
an edge case.

Fixed across parser/index.ts and compile.ts:
- parseBlock now accepts a `fromIndex` to resume searching partway
  through the source and reports where its match ended, enabling a new
  findAllBlocks() that repeatedly calls it to collect every occurrence
  of a tag - used for <style> specifically (template/script remain
  single-block, matching how this framework actually uses them).
- SFCResult gained `styleBlocks: Array<{content, lang, scoped}>` with
  the complete list, in source order; the existing singular
  `style`/`styleLang`/`styleScoped` fields still reflect just the first
  block, unchanged, for any code already reading those.
- compile() now compiles every block, each respecting its own `scoped`
  attribute independently, and concatenates the resulting CSS - so a
  scoped block and a global block in the same file correctly produce
  scoped and unscoped CSS respectively, side by side.
- The trickier part: multiple *scoped* blocks in the same file need to
  share exactly one scope id, not each compute their own independently.
  The template compiler stamps every element with a single scope
  attribute, so if two scoped blocks ended up with different ids (which
  they would, if each one's id were derived only from its own CSS text),
  only one of them would ever actually match a rendered element - the
  same category of bug an earlier commit's scoped-CSS fix addressed for
  the single-block case. Fixed by computing one shared scope id per file
  from the filename plus the combined text of all style blocks, used by
  every scoped block and the template alike.

Verified: a file with one scoped + one global block now produces both,
correctly scoped/unscoped respectively; two scoped blocks in the same
file share the identical scope id, confirmed matching the actual
`data-teloce-*` attribute the template stamps onto its elements; the
original single-style-block case is completely unchanged (same scope id
format, same output); a file with no <style> block at all still
correctly returns undefined with no errors.

Verified: full regression sweep across everything from this session and
previous ones (lifecycle hooks, unkeyed for-loops, :class, :style,
nested for-loops, whitespace, list-ordering, component composition,
custom directives, global state) still all passes, plus a full
"pnpm -r build" across the whole workspace with zero errors.
@aldanedev-create
aldanedev-create merged commit d159f0d into main Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant