🐛 BUG: Unable to use custom `.foo.scss` loader in build mode
What version of astro are you using?
1.0.0-beta.72
Are you using an SSR adapter? If so, which one?
None
What package manager are you using?
npm
What operating system are you using?
Linux
Describe the Bug
I have added a custom .scss loader to my project intended to be used with Lit elements.
Basically, when a file that ends in .lit.scss is loaded, I want to return custom JavaScript rather than having the file hoisted into the page, or treated as a CSS module. I want neither behavior to happen, and I just want to handle the loading and usage of this file entirely myself.
In dev mode, everything works fine, except the asset is hoisted (even though I don't want it to be). See screenshot below.

Question
Is there a way to tell Astro not to hoist/inject these files? I wonder if that will fix my issue.
Problem
When running npm run build, because Astro is trying to hoist or inject the CSS instead of let me process it, the .mjs file that is supposed to be generated by my plugin is not being emitted, and then the build fails (see traceback below).
I also believe if I just use a custom extension entirely (like .lit with no terminating .scss), this would work fine. I think I need a way to tell Astro/Vite (?) to let me process my file and not handle it using its defaults.
$ npm run build
> @example/[email protected] build
> astro build
12:23:27 PM [build] Collecting build information...
12:23:27 PM [build] Completed in 36ms.
12:23:27 PM [build] Building entrypoints for prerendering...
12:23:28 PM [build] Completed in 1.00s.
generating static routes
▶ src/pages/index.astro
node:internal/errors:464
ErrorCaptureStackTrace(err);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/jeremydw/git/github-uyp4dd/dist/chunks/c3781653.fb266ed8.mjs' imported from /Users/jeremydw/git/github-uyp4dd/dist/chunks/button.97e7b2c0.mjs
Link to Minimal Reproducible Example
https://stackblitz.com/edit/github-uyp4dd-uvcsde
Participation
- [ ] I am willing to submit a pull request for this issue.
FYI; a similar issue may have existed in https://github.com/withastro/astro/issues/2766#issue-1166529448 but it looks like that was resolved through a Vite upgrade. I am wondering if the root cause is the same.
Update: Using ?inline prevents the injection/hoisting into the page. The issue with the .js file not being emitted and npm run build still remains.
FYI; I was able to fix this in build mode by going into Astro's code and changing the logic around isCSSRequest.
- https://github.com/withastro/astro/blob/main/packages/astro/src/vite-plugin-build-css/index.ts#L62
- https://github.com/withastro/astro/blob/main/packages/astro/src/core/render/util.ts#L48
When I altered this to exclude .lit.scss as a CSS file type, Astro no longer treated my files as CSS (which is correct, since my custom loader generates JS), and it emitted the chunks correctly and the build worked.
So, maybe this is a feature request? I think I may need a way to indicate to Astro that my file that ends in .css (for me, technically it's .lit.scss) is transformed into JS by my custom loader/plugin and therefore shouldn't be handled as CSS in Astro.
FYI: I'm not sure if my patch had side effects but it allowed my example to work in both dev mode and build mode.
Thanks for opening an issue @jeremydw! I think your diagnosis is correct, there's currently not a way to signal to Astro that a CSS-like file shouldn't be handled by us.
Curious to hear what kind of hook you think would be ergonomic for this... Is the ?inline param something you made up or is it a Vite feature? It might make sense for us to officially support a param similar to ?inline.
I actually have no idea where I discovered ?inline but I was just trying various things after Googling and noticed that adding ?inline prevented the hoisting to the head. If it's not an Astro feature it must be a Vite feature, I'm guessing.
I do have an update to share since I filed this issue originally. Last night I developed a workaround for the issue by altering my Vite plugin. I added two steps to the Vite plugin to workaround the behavior in Astro:
- I updated the
resolveIdhook to virtually rename the file to end in.scss.js. - In the
loadhook, I check for.scss.jsfiles and load them manually (after replacing the filename back to its original filename).
You can check it out here: https://gist.github.com/jeremydw/946d5a9f35ee1e5b9952285f55e38877
This actually seems to work perfectly fine for me and I haven't seen any side effects (although I only reached this conclusion last night and haven't had a chance to test it extensively).
That said, despite the workaround, I think there may be a need to indicate to Astro how to treat files that are generated with custom loaders/plugins. For example, if I have a custom plugin that emits bonafide CSS modules, I think it'd be good to indicate that to Astro somehow.
Maybe there's some community query parameter convention to indicate what the resulting file type is?
import styles from './foo.lit.scss?type=js`
It seems kind of bizarre to me, though.
I think probably the "cleanest" way would to be add the ability in the Astro config setup hook to be able to specify the CSS file type regex. Then I could exclude .lit.scss from being treated as CSS by Astro.
By the way, thanks for the discussion!