# DISCUSSION: Qwik Component Stylesheet Handling ###### tags: qwik ## Overview Brainstorm how should Qwik handle component stylesheets ## Requirements 1. Stylesheets should be lazy loaded only when needed - SSR code will have both the `<style>` as well as the component already in the HTML. If the component needs to be re-rendered the component template needs to be downloaded. Downloading the template should not require re-downloading the CSS (because it is already in the `<style>` doe to SSR.) 3. Stylesheets should be scoped to the component ## Ideas A list of ideas to discuss on how such code should work. ### Scoping Stylesheet to the Component - Each element in the component will need a custom class to narrow down the stylesheet to just that component - The custom class name should be the SHA of the component path? But only `n` (6?) characters and all `a-z0-9` alphanumeric letters. (`36^6 = 2,176,782,336` extremely low chance of collision) For example: `A0Q1X3` - Components will need to declare their ID This will allow the host element to know which stylsheet needs to be downloaded (and if it needs to be downloaded) ```html <div decl:template="./MyComponent#A0Q1X3" class="A0Q1X3"> ``` - The insertion of the host element should trigger checking if a given stylesheet is already loaded and if not it should be loaded. > **Open Questions** > - Should the component QRL be the component SHA always? (Since it is kind of duplicate information?) ### Downloading Stylesheet only when needed - Component is recognized by `<div decl:template="./MyComponent#A0Q1X3">`. We could institute a rule that the component's stylesheet is same QRL with `.css` suffix resulting in `./MyComponent.css` - Only download the stylesheet on first render. (Subsequent renderings do not need stylsheet downloaded because it already has been downloaded and inserted into `<head>`) - A stylesheet is inserted into `<head>` either directly or as a link so: ```html <head> ... <style decl:style="A0Q1X3">...</style> <link decl:style="A0Q1X3" href="./MyComponent.css" rel="stylesheet"> </head> ``` - In both cases we need to include `decl:style="A0Q1X3"` so that the rendering system can easily determine if the stylesheet is already present upon Qwik resume. Upon first render Qwik can execute `querySelectorAll('[decl\\:style="A0Q1X3"]')` to determine if the stylsheets needs to be downloaded. - `<style>` has advantage of inlining hence faster startup - `<link>` has advantage of caching - Both approaches should work ### Open Questions - Would it be possible to have the tooling warn on unused styles? How would we know that the styles are unused? - At times it is useful to be able to add styles programmatically to the components. How could we add such styles in lazy way. ### Static vs dynamic styles - component styles which are in the `<style decl:style="A0Q1X3">` should be static. What we mean by that is that all of these styles need to be present for the component to render properly. - At times it is desirable to have dynamic styles ```typescript function MyComponent() { return <span class={expr ? FOO : ''}></span> } ``` In the above example `FOO` is added dynamically. - It means that it is not possible to statically determine if the `FOO` class should be included in the `<style>` tag. Hence no way to know if there are unused classes in the `<style>`. - Is it worth going through the trouble of lazy loading `FOO`? - Maybe we separate things into static styles and dynamic styles. Static styles are included in `<style>` where as dynamic styles are inlined into the `.js` code? --- ```typescript= // ==> Should produce a ObjectLiteral representing the style // import * as HelloWorld_css from 'HelloWorld.css'; // Seems unecessary type HelloWorld = QComponent<{}, {}> const HelloWorldState = qrlState<HelloWorld>(() => {}); // TOOLING: const HelloWorldState = qrlState<HelloWorld>(QRL`chunk_abc#state`); // const HelloWorldStyle = qrlStyle<HellWorld>(HelloWorld_css); const HelloWorldStyle = qrlStyle<HellWorld>('./HelloWorldStyle.css'); const HelloWorldStyle = qrlStyle<HellWorld>(import('./HelloWorldStyle.css')); // TOOLING: const HelloWorldStyle = QRL`./chunk_abc#CSS?scopeId=abc123`; const HelloWorld = qComponent({ state: HelloWorldState, style: HelloWorldStyle, view: HelloWorldView }) ``` ```css= .some-class {...}; :host.some-class2 {...}; ``` ```typescript= // chunk_abc.js export const CSS = ` .🏷️abc123.some-class {...} .📦abc123.some-class2 {...} `; export const state = () => {} ``` Requirements: - Lazy load the styles - Generate unique IDs for each component - Munge the styles with ID prefix