qwik
qwik copied to clipboard
Pure qwik app/library: CSS from library doesn't load in the app by default
Qwik Version
0.0.39
Operating System (or Browser)
windows
Node Version (if applicable)
No response
Which component is affected?
Qwik Rollup / Vite plugin
Expected Behaviour
- Create a component library from starter and add a component which imports styles in module.css.
- Build the component library to produce the
/lib/
folder content. This produces a concatenated .css file. - Create a qwik app and npm link to the library. Add the component to your page.
Expected: Component renders and is styled.
Actual Behaviour
Component renders and is missing styling. It is ok if there is a manual step here as long as it's documented somewhere, but I'm not sure what the strategy currently is. Either it should just work, or there should be some docs here.
I also want to suggest: concatenating the css at the library layer seems less ideal. If I export 20 components and the consumer uses 3 of them, I'd prefer to only have 3 modules worth of styling processed.
A better approach perhaps: let the library emit extractable but functional intermediate output so that optimization can happen later. Make the app build extract the module css referenced in the build graph and do this work once we understand the bundle output.
This essentially is what we are working on here: https://github.com/microsoft/griffel (runtime injectable css but extractable at app build time.) Similar to stylex from facebook or Linaria.
Additional Information
No response
I will look into this issue this weekend, can you share a small component that reproduces the issue?
@manucorporat Created a small repro repo here: https://github.com/dzearing/qwik-library-styling-repro
README explains everything; look for the "red background Counter". Works in isolation within the library, but styling won't come along to the app on usage.
@manucorporat did you get anywhere on this one?
@dzearing I think it makes sense to update the example to the current qwik version - just to make it easier to look at it
@dzearing the .css inclusion is done by Vite I think, and apparently it doesn't do that for libraries?
In any case, it's probably a better approach to insert the style with useStyles$
, that way it's only added when used.
Hi @dzearing 👋 Does any of the provided tipps helped to solve the issue?
Not sure if this will help but hopefully additional context helps: Astro also has issues with CSS-in-JS tools and it's related to how Vite works. Hopefully some of the other tools dedicated Vite plugins can help!
I love how fast Vite is but it's always been a constant pain for me whenever trying to do CSS with tooling beyond Tailwind or CSS Modules.
Almost have a similar issue with combination of qwik component lib in NX monorepo and using tailwind in that. Tailwind styles won't be picked up from component library unless I use same tailwind classes in another component in the quick city project. After that even if I remove the component tailwind styles remains on the document and applies correctly till restarting qwik city project.
Project structure: NX monorepo -> app/my-qwik-app (uses tailwind) -> libs/my-qwik-lib (uses tailwind but styles won't be picked up unless they are being used in my-qwik-app and works in dev even after removing usages till next restart)
I was trying this with qwik 1.0.0
Hi @dzearing 👋 Did you solve the problem?
I have the same issue. For now I add all needed classes in safelist in tailwind.config.js in my app just to get it going, but would love a better solution?
Lib mode is completely broken. Does anyone have any workaround for this issue?
@zanettin sorry for the slow response! I missed the notifications. I hadn't gotten anywhere on this, and just tried latest qwik with the same repro.
(cc @noeliadv - nope, hopefully we can find a solution here.)
OK so I did manage to get some styles rendering in the host app, but it needs some automation I think. Maybe a better solution.
I'm not 100% familiar with how vite/qwik plugin css extraction might emit results, but after yarn build
in the library folder, I see a lib/build/q-00e5211c.css
file with the raw css styling. this is what we need to inject into the app.
The first challenge is how to access this styling from the app. I manually adding an exports
path to resolve this file easily from an external consuming package:
{
...,
"./styles.css": "./lib/build/q-00e5211c.css"
}
That means at the app level, I can pull styles manually:
// ...
import styles from 'qwik-library/styles.css';
export default component$(() => {
useStyles$(styles);
}
This populated the styles the library defined in the host app. That said, it's probably not the right solution, but a workaround.
- I don't know how many of these css files could be generated. Will multiple css files be emitted as I add more components or async imports creating split points?
- As a consumer, I'd prefer to just import a component and only have THAT component's css be in my final page load - not every component in the library. How can we maintain the tiniest impact on the library styling to the app's page load?
@dzearing checking to make sure: are the files that contain Qwik components and import css named as .qwik.(m)js?
That's necessary for the optimizer to work. However, importing css should normally be handled by vite, so probably that's not what's wrong.
I don't think so. At least, the boilerplate "component library" template components which npm create qwik@latest
produces look like this:
But... none of the files in the example are named .qwik.*
(or load css.) I can try to change my component name and see what happens.
I think the optimizer, or at least css extraction, really should not be operating on a component library. The component library is going to produce an intermediate npm package that should be easy to consume. It should (for dev mode) be bundlable as a standalone esm package, with css embeded in the js so that consumers don't need to fuss with loading css assets.
Then at the app layer, particularly for production builds, we run optimizer and css extraction, and other nice things like tree shaking and common chunks. These are slow (but awesome and critical) linear scale monolithic steps that need the full graph of information to make decisions.
Bascially - building a library should have a different set of steps than building an app. I think right now they might be the same.
@wmertens I did try to rename my button.tsx
to button.qwik.tsx
but no change. The component-library demo app gets styles. The app importing the button does not get button styles without the workarounds.
Hmm, there's a couple of moving parts here.
- An npm package that contains qwik components should name those files
filename.qwik.js
. So not the source files but the built library files - Vite is configured so that any
.css
import will be added to the global CSS file. I'm not sure if this also happens for imports under node_modules, probably not. - A way to force CSS loading on first use is
useStyles$
, which can be used inside of imported modules, provided they are named*.qwik.js
So, if you want to magically provide CSS for your user, your components should use useStyles$
. Otherwise, you provide a .css
file for them to import, and they can decide whether to use useStyles$
or add to their global .css themselves.
PS: Here it tests for .qwik.js https://github.com/BuilderIO/qwik/blob/270a7beaf9efd733849af946ab14eb15c8e7362d/packages/qwik/src/optimizer/src/plugins/plugin.ts#L564 - needed because library files can't have a .tsx extension
Thank you @wmertens it works for me! :)
@dzearing did you try the @wmertens solution? is it working for you?
Re checking - @dzearing any update here? did the solution work for you?
If it is, I'm marking this resolved.
in case the solution doesn't work, please re-open.