Repository navigation
feat(lint): warn when a scene's styles sit outside its template - #6317
Conversation
A sub-composition file with a <template> is mounted from the template alone, so a <style> in its <head> (or a stylesheet link in its body) never applies in preview, snapshot or render. Warn on it, with the fix in the message: move it inside <template>.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
There was a problem hiding this comment.
Verdict: APPROVE · 0 blocker · 0 important · 0 nits · head 4210097e
I checked the rule against all three mount paths: planCompositionAssembly, which sets assetHead = hasTemplate ? null : head and hoists linkSources from head; the preview compositionLoader, where the first or #<id>-template makes the file templated; and the render path's resolveSubCompositionContent. They agree with what the rule flags. The four new tests and the 300 tests in composition.test.ts pass locally. I also probed edge cases: <style> text inside a <script> string is not flagged, a <style> inside <noscript> in <head> is flagged (correct, it is dropped too), and so is a bare <link><template> fragment with no <head> (correct for render, because linkedom puts no head links there).
Scope
I read the whole diff (3 files). CI was still running at review time and no check had failed. There were no prior reviews.
Edit accuracy: accurate 271 (base branch 271), smooth 144 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (3)
|
What
hyperframes lintnow warns when a sub-composition file that has a<template>keeps a<style>outside it, or a<link rel="stylesheet">outside both the template and<head>. The message says to move it inside<template>.Why
A templated sub-composition is mounted from its template alone, so styles left outside it never apply. The scene renders unstyled in preview, snapshot and render alike, with no error. The usual shape is a full HTML page with its
<style>in<head>and the composition root in a<template>in<body>.Dropping the head is deliberate, and every mount path shares it:
packages/core/src/compiler/compositionAssembly.ts:238-239:assetHead = hasTemplate ? null : head, so head<style>and<script>are left out for a templated composition (styleSources, lines 247-250).packages/core/src/runtime/compositionLoader.ts:795-808(preview) andpackages/parsers/src/subCompositionValidity.ts:61-63, used bypackages/core/src/compiler/inlineSubCompositions.ts:417(render): any<template>in the file makes it templated, and only its content is mounted.Head stylesheet links are different:
linkSources(compositionAssembly.ts:252-255) readshead, notassetHead, so<link rel="stylesheet">and<link rel="preconnect">in<head>are always hoisted. The rule leaves those alone and only flags a stylesheet link in the body outside the template.Scoping head styles into the composition instead was ruled out: the head belongs to the host page by design (the comment at line 238), so the fix is a warning at authoring time.
How
subcomposition_style_outside_templateinpackages/lint/src/rules/composition.ts, active only for sub-composition files (isSubComposition, set forcompositions/*bypackages/lint/src/project.ts:261).tagsare the template's content once the root lives inside it (packages/lint/src/context.ts:46-52).isInsideInertTemplatenow delegates to a smallisInsideTag(tag, tags, name)so the head check reuses it.docs/reference/lint-rules.mdx.Every tracked templated file under a
compositions/folder in this repo (124) lints clean with the rule.Test plan
Unit tests added/updated
Manual testing performed
Documentation updated (if applicable)
Comments follow CONTRIBUTING.md "Comments": they say why, not what, and a bug fix says what the code must do and how to reproduce the bug
composition.test.ts, 4 tests: a head<style>next to a<template>warns with the fix in the hint; a<style>and a stylesheet link in the body outside the template each warn; styles inside the template and a head stylesheet link do not; a file without a template, or outside a sub-composition, does not.With the rule returning nothing, the two warning tests fail. Removing each guard in turn (the head-link exclusion, the template exclusion, the sub-composition check, the template check) fails the matching negative test.
packages/lintsuite: 22 files, 1,169 tests, 3 runs in a row, exit 0. Pre-commit lint, format, typecheck and fallow pass;check-comment-citationsandcomment-ratchetpass.