withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!
https://astro.build
Other
46.82k stars 2.49k forks source link

"switch/case" component bundles scripts for all cases #8223

Closed y-nk closed 1 year ago

y-nk commented 1 year ago

Astro info

Astro version            v2.10.14
Package manager          npm
Platform                 linux
Architecture             x64
Adapter                  Couldn't determine.
Integrations             @astrojs/react

What browser are you using?

stackblitz

Usecase

I'm making a Map<string, AstroComponent> which i use to switch between multiple implementations of a single component based on an enum, something like:

type Carousel = {
  viewType?: 'standard' | 'not-animated' | 'infinite-loop'
}

...which ends up switching between <StandardView />, <StaticView /> and <LoopView /> components.

Describe the Bug

I have found that when doing something such as:

---
import View1 from './View1.astro'
import View2 from './View2.astro'
import View3 from './View3.astro'

export type Props = {
  type?: 'view1' | 'view2' | 'view3'
}

const View = (
  Astro.props.type === 'view3' ? View3 :
  Astro.props.type === 'view2' ? View2 :
  View1
)
---

<View><slot /></View>

...the <script> tags of View1 View2 and View3 are inserted in the page, even tho only the html corresponding to the switch/case is actually rendered.

Non working workarounds

I have tried different syntax as workaround but they don't work.

In template switch/case

---
import View1 from './View1.astro'
import View2 from './View2.astro'
import View3 from './View3.astro'

export type Props = {
  type?: 'view1' | 'view2' | 'view3'
}
---

{
  Astro.props.type === 'view3' ? (
    <View3><slot /></View3>
  ) :
  Astro.props.type === 'view2' ? (
    <View2><slot /></View2>
  ) : (
    <View1><slot /></View1>
  )
}

→ still bundle the js of the 3 versions

Dynamic import

---
export type Props = {
  type?: 'view1' | 'view2' | 'view3'
}

const mod = (
  Astro.props.type === 'view3' ? 'View3' :
  Astro.props.type === 'view2' ? 'View2' :
  'View1'
)

const { default: View } = await import (
  `./${mod}.astro`
)
---

<View><slot /></View>

bundle it all

---
export type Props = {
  type?: 'view1' | 'view2' | 'view3'
}
---

<div data-type={Astro.props.type}><slot /></div>

<script>
  import view1 from './view1.ts'
  import view2 from './view2.ts'
  import view3 from './view3.ts'

  const behaviors = { view1, view2, view3 }

  document.querySelectorAll<HTMLElement>(div['data-type'])
    .forEach(view => {
      const type = view.getAttribute('data-type')!
      behaviors[type](view)
    })
</script>

→ bundles it all but at least execution is regulated from userland code. → DOM of different view1/view2/view3 cannot be separated, or must be in a ternary

What's the expected result?

We should only have the Githubissues.

  • Githubissues is a development platform for aggregating issues.