-
-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Description
Astro Info
Astro v5.17.3
Vite v6.4.1
Node v20.19.1
System Linux (x64)
Package Manager npm
Output static
Adapter none
Integrations none
If this issue only occurs in one browser, which browser is a problem?
n/a
Describe the Bug
Prior to Astro 5.16.9, a <script> in a component would be rendered adjacent to that component.
For example, the following component:
<p>Example</p>
<script>console.log('hello')</script>would be rendered to something like:
<p>Example</p>
<script type="module" src="/some/path/to/the/built/script.js"></script>In basic cases, this is still the case but #15147 changed logic when rendering happens via a slot.
For example, if the component above is passed as a child to this component:
---
const html = await Astro.slots.render('default');
---
<p>Parent example</p>
<Fragment set:html={html} />Then the output is something like:
<p>Parent example</p>
<script type="module" src="/some/path/to/the/built/script.js"></script>
<p>Example</p>Note how the <script> moved in front of the <p>Example</p>.
More extreme cases can see the script moved up the HTML tree entirely for example the following input in the minimal reproduction where ComponentB contains a script and ComponentA uses the Astro.slots.render() pattern:
<ComponentA>
<ol>
<li>Some text</li>
<li><ComponentB /></li>
</ol>
</ComponentA>In this case, the script from ComponentB gets rendered before the opening <ol> tag.
This can cause issues for things like CSS where :first-child and other child and sibling selectors may not expect a script from a child component to appear. In withastro/starlight#3712 it broke Starlight components due to expectations about the HTML output Astro would produce.
It’s also harder to work with this behaviour because it’s unpredictable: where the <script> is rendered depends on how the component is rendered.
What's the expected result?
I would expect the <script> to be rendered in a consistent location. Ideally it should not be rendered “outside” of its own tree because doing so forces users to design parent components to handle the “risk” that a child might contain a <script> that could show up in an unexpected location. That kind of “defensive” pattern is a DX smell.
Link to Minimal Reproducible Example
Participation
- I am willing to submit a pull request for this issue.