qwik icon indicating copy to clipboard operation
qwik copied to clipboard

Pure qwik app/library: CSS from library doesn't load in the app by default

Open dzearing opened this issue 2 years ago • 8 comments

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

  1. Create a component library from starter and add a component which imports styles in module.css.
  2. Build the component library to produce the /lib/ folder content. This produces a concatenated .css file.
  3. 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

dzearing avatar Aug 05 '22 19:08 dzearing

I will look into this issue this weekend, can you share a small component that reproduces the issue?

manucorporat avatar Aug 08 '22 16:08 manucorporat

@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.

dzearing avatar Aug 08 '22 18:08 dzearing

@manucorporat did you get anywhere on this one?

dzearing avatar Oct 10 '22 16:10 dzearing

@dzearing I think it makes sense to update the example to the current qwik version - just to make it easier to look at it

wtho avatar Oct 10 '22 18:10 wtho

@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.

wmertens avatar Nov 14 '22 11:11 wmertens

Hi @dzearing 👋 Does any of the provided tipps helped to solve the issue?

zanettin avatar Feb 10 '23 23:02 zanettin

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.

soluml avatar Feb 16 '23 02:02 soluml

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

faridarzpeyma avatar May 08 '23 04:05 faridarzpeyma

Hi @dzearing 👋 Did you solve the problem?

noeliadv avatar Jun 29 '23 16:06 noeliadv

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?

limotek avatar Jul 25 '23 16:07 limotek

Lib mode is completely broken. Does anyone have any workaround for this issue?

motss avatar Sep 23 '23 18:09 motss

@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.)

dzearing avatar Sep 29 '23 15:09 dzearing

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.

  1. 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?
  2. 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 avatar Sep 29 '23 16:09 dzearing

@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.

wmertens avatar Sep 29 '23 21:09 wmertens

I don't think so. At least, the boilerplate "component library" template components which npm create qwik@latest produces look like this:

image

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.

dzearing avatar Sep 30 '23 00:09 dzearing

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.

dzearing avatar Sep 30 '23 00:09 dzearing

@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.

dzearing avatar Sep 30 '23 00:09 dzearing

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

wmertens avatar Sep 30 '23 05:09 wmertens

Thank you @wmertens it works for me! :)

EggDice avatar Oct 23 '23 20:10 EggDice

@dzearing did you try the @wmertens solution? is it working for you?

gioboa avatar Dec 29 '23 10:12 gioboa

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.

hamatoyogi avatar Jan 23 '24 09:01 hamatoyogi