Astro Info
Astro v5.7.13
Node v20.19.0
System macOS (arm64)
Package Manager pnpm
Output server
Adapter astro-sst
Integrations astro-icon
htmx
posthogJs
@astrojs/partytown
If this issue only occurs in one browser, which browser is a problem?
Chrome, Brave, likely all
Describe the Bug
Problem
Consider two Astro components such that the InnerComponent is placed inside OuterComponent using slots. Suppose the InnerComponent has at least one script associated with it.
<!-- OuterComponent.astro -->
<outer-component>
<h2>OuterComponent</h2>
<slot />
</outer-component>
<script>
console.log('OuterComponent connected')
</script>
<!-- InnerComponent.astro -->
<inner-component>
<h3>InnerComponent {Astro.props.idx}</h3>
</inner-component>
<script>
console.log('InnerComponent connected')
</script>
The script inlining behavior does not following expected ordering rules in two usage scenarios, both of which involve async execution and templates.
Scenario 1: async string
---
import OuterComponent from '../comps/OuterComponent.astro'
import InnerComponent from '../comps/InnerComponent.astro'
// Any word containing 'a w a i t' (no spaces) as a substring causes the bug to appear.
// Editing the string below, without removing the comment, or deleing the line
// results in the disappearance of the bug:
// await
---
<Layout>
<OuterComponent>
<InnerComponent idx={1} />
</OuterComponent>
<template>
<InnerComponent idx={2}/>
</template>
</Layout>
I noticed this scenario first in a more realistic situation: awaiting server data. In the process of debugging, I realized that I could reproduce this bug with only the text async inside a comment.
Scenario 2: Promise block
---
import OuterComponent from '../comps/OuterComponent.astro'
import InnerComponent from '../comps/InnerComponent.astro'
---
<Layout>
<OuterComponent>
{Promise.resolve(1).then((i) => <InnerComponent idx={i} />)}
</OuterComponent>
<template>
<InnerComponent idx={2}/>
</template>
</Layout>
The Result (Either Scenario)
The script is inlined within the template tag, instead of after first usage of the component. As a result, the scripts do not run.

Context
I ran into this when using web components in a nested list. Because of this issue my web component never registers, meaning items outside the template have no interactivity. I also noticed the icons inside the impacted component failed to load.
This is related to #13795 in that async behavior appears to cause the inlining to occur in the template tag.
Workaround
The simplest workaround is to leave the async in the frontmatter and load the template scripts into the body once the page has loaded:
const location = window.location.href
document.addEventListener('astro:page-load', () => {
if (location === window.location.href) {
const itemTempl = document.getElementById('account-item-template') as HTMLTemplateElement
const frag = itemTempl.content.cloneNode(true) as DocumentFragment
frag.querySelectorAll('script').forEach((s) => {
document.body.appendChild(s)
})
}
})
Alternatively, you can refactor your frontmatter to work with promises (removing the async keyword) and then include a hidden instance of your component before the async promise block. In this scenario, the hidden component will provide the inlined script.
Analysis
From what I can tell, the inlining will not occur as expected if all of he following are true:
- this component is in a slot
- the string 'await' appears in parent component (frontmatter or html, before or after component usage) or the component is used inside an Promise (ex.
somePromise.then((p) => <MyComponent ...p />)
- the component used in a template
The async in the comment in a frontmatter was very odd behavior. I don't know enough about the project internals, but that makes me think it may be a compiler issue. Paired with the Promise behavior, it seems like the component script inlining behavior is connected to async blocks.
What's the expected result?
The expected behavior is hard to discuss without also discussing #13795. I expect that in the following setups my scripts are inlined such that the component scripts are run at least once.
Await Scenario
---
const data = await serverData()
---
<Layout>
<OuterComponent />
<InnerComponent data={data} />
<OuterComponent />
<template>
<InnerComponent />
</template>
</Layout>
Promise Scenario
---
const dataPromise = serverData()
---
<Layout>
<OuterComponent />
{dataPromise.then((data) => <InnerComponent data={data} />)}
<OuterComponent />
<template>
<InnerComponent />
</template>
</Layout>
Link to Minimal Reproducible Example
https://stackblitz.com/edit/github-x42aukcv?file=src%2Fpages%2Findex.astro
Participation
Astro Info
If this issue only occurs in one browser, which browser is a problem?
Chrome, Brave, likely all
Describe the Bug
Problem
Consider two Astro components such that the
InnerComponentis placed insideOuterComponentusing slots. Suppose theInnerComponenthas at least one script associated with it.The script inlining behavior does not following expected ordering rules in two usage scenarios, both of which involve async execution and templates.
Scenario 1:
asyncstringI noticed this scenario first in a more realistic situation: awaiting server data. In the process of debugging, I realized that I could reproduce this bug with only the text
asyncinside a comment.Scenario 2:
PromiseblockThe Result (Either Scenario)
The script is inlined within the template tag, instead of after first usage of the component. As a result, the scripts do not run.

Context
I ran into this when using web components in a nested list. Because of this issue my web component never registers, meaning items outside the template have no interactivity. I also noticed the icons inside the impacted component failed to load.
This is related to #13795 in that async behavior appears to cause the inlining to occur in the template tag.
Workaround
The simplest workaround is to leave the
asyncin the frontmatter and load the template scripts into the body once the page has loaded:Alternatively, you can refactor your frontmatter to work with promises (removing the
asynckeyword) and then include a hidden instance of your component before the async promise block. In this scenario, the hidden component will provide the inlined script.Analysis
From what I can tell, the inlining will not occur as expected if all of he following are true:
somePromise.then((p) => <MyComponent ...p />)The
asyncin the comment in a frontmatter was very odd behavior. I don't know enough about the project internals, but that makes me think it may be a compiler issue. Paired with thePromisebehavior, it seems like the component script inlining behavior is connected to async blocks.What's the expected result?
The expected behavior is hard to discuss without also discussing #13795. I expect that in the following setups my scripts are inlined such that the component scripts are run at least once.
Await Scenario
Promise Scenario
Link to Minimal Reproducible Example
https://stackblitz.com/edit/github-x42aukcv?file=src%2Fpages%2Findex.astro
Participation