withastro / astro

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

`js?url` import fails during build #11328

Closed wirhabenzeit closed 3 days ago

wirhabenzeit commented 4 days ago

Astro Info

Astro                    v4.11.0
Node                     v20.10.0
System                   macOS (arm64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             astro-expressive-code
                         astro-icon
                         @astrojs/tailwind
                         @astrojs/sitemap
                         @astrojs/mdx

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

Importing a js-file with the ?url directive and then passing the string to a child component works in dev mode but breaks in build mode.

I have three files

pages/
     index.astro
     script.astro
components/
     Component.astro

with the content

// script.ts
export const hello = (user: string) => 'Hello, ' + user + '!';
// Component.astro
---
const { ref } = Astro.props;
const { hello } = await import(/* @vite-ignore */ref);
---

<div>{hello("Server")}</div>
<div id="clientdiv"></div>

<script define:vars={{ ref }}>
    import(/* @vite-ignore */ref).then((module) => {
        document.querySelector("#clientdiv").textContent = module.hello("Client");
    });
</script>
// index.astro 
---
import Component from '../components/Component.astro';
import ref from './script.ts?url';
---

<Component ref={ref} />

This works in dev mode but breaks during build with error Cannot find module '[...]/_astro/script.CnRJZ0uG.ts'

What's the expected result?

The expected result is

Hello, Server!
Hello, Client!

My goal here is to have a piece of code which is executed during build but potentially also on the client for user interactivity. I know that only serialisable objects can be passed to client components, that's why I am trying to import the same external script in both places. This approach works if I hard-code "script.ts" in Component.astro but I would like to have a generic component.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/withastro-astro-inw9ut?file=src%2Fcomponents%2FComponent.astro

Participation

bluwy commented 3 days ago

?url is a Vite feature that only works on the client side, so after bundling, you'd get a URL string that'll only work on the client-side script. It works coincidentally in dev for Vite in the server, but perhaps you can submit an issue to Vite to properly support it in build too.

Even after getting that to work, you may hit this error (https://github.com/vitejs/vite/issues/9952), which is unfortunately also not fixed in Vite yet.

As a workaround, I'd suggest refactoring and avoid ?url for .js and .ts files for now, and try to pass the actual values from the module instead.

As there's not much Astro can fix here (with it mostly controlled by Vite), I'll close this for now.