Feature Design: JIT CSS Optimization
Target Version: v1.2
Status: Draft
This document outlines the design specifications for adding an automatic CSS optimization engine to Violetear. This feature ensures that Server-Side Rendered (SSR) pages serve the absolute minimum amount of CSS required to render the content, significantly improving First Contentful Paint (FCP) and reducing network usage.
Objective
Implement a pipeline that scans the generated HTML (Document object model), identifies the CSS classes actually in use, and generates a minimal CSS subset on the fly to be inlined directly into the response.
1. Scanner Logic (violetear.markup)
We need a reliable way to traverse the Violetear component tree and extract all class names referenced by the elements.
1.1 Element.scan_classes()
- Responsibility: Recursively collect all tokens in
self.classes from the element and all its children.
- Returns:
Set[str] to ensure uniqueness.
(Note: Basic implementation already exists in the current codebase, but needs to be formalized and tested against Component subclasses).
1.2 Document.get_used_classes()
- Responsibility: Entry point for the App to request the usage set from the entire document body.
2. Filter Logic (violetear.stylesheet)
The StyleSheet class needs a new rendering mode that accepts a filter.
2.1 StyleSheet.render_subset(used_classes: Set[str]) -> str
- Input: A set of class names (strings) found in the document.
- Logic:
- Iterate over all stored
Style objects.
- Check the
Selector of each style.
- Inclusion Criteria:
- If the selector targets a Tag (e.g.,
body, h1), always include (global styles).
- If the selector targets an ID (e.g.,
#header), always include (specific styles).
- If the selector targets Classes (e.g.,
.btn.primary):
- Include ONLY if all classes in the selector are present in
used_classes.
- Example: Rule
.btn.primary is kept only if both btn and primary are used.
- Animations: If a style is included and it uses an
@keyframes animation, that animation definition must also be included in the output.
- Output: A string containing only the valid CSS rules.
3. Server-Side Integration (violetear.app.App)
The App class handles the request/response lifecycle and decides how to serve the CSS.
3.1 Routing Logic Update
We will update the route wrapper to support a mode switch (e.g., jit=True or default behavior for non-PWA routes).
Workflow:
- Execute user view function -> Get
Document.
- Scan: Call
doc.get_used_classes() to get the set of active tokens.
- Process Assets: Iterate through
doc.head.styles.
- If the resource is a
StyleSheet object (not a string URL):
- Call
sheet.render_subset(used_classes).
- Replace the
<link> tag in the header with a <style> tag containing the optimized CSS string.
- If the resource is a URL (CDN/Static file):
- Leave as is (cannot optimize external resources).
- Return: Send the optimized HTML response.
3.2 Caching Considerations (Future)
- For high-traffic production, we might want to cache the generated CSS string based on a hash of the
used_classes set to avoid re-filtering the stylesheet on every request.
4. Usage Example
No changes required in user code! The optimization happens transparently.
# User defines a massive theme (e.g. Atomic/Tailwind preset with 10,000 rules)
app.add_style(Atomic())
@app.route("/")
def home():
# User uses only 2 classes
return Document().add(Element("div", classes="text-xl text-red"))
# RESULT:
# The browser receives an HTML with a <style> block containing
# ONLY the rules for .text-xl and .text-red.
# The other 9,998 rules are discarded.
5. Task List
Feature Design: JIT CSS Optimization
Target Version: v1.2
Status: Draft
This document outlines the design specifications for adding an automatic CSS optimization engine to Violetear. This feature ensures that Server-Side Rendered (SSR) pages serve the absolute minimum amount of CSS required to render the content, significantly improving First Contentful Paint (FCP) and reducing network usage.
Objective
Implement a pipeline that scans the generated HTML (Document object model), identifies the CSS classes actually in use, and generates a minimal CSS subset on the fly to be inlined directly into the response.
1. Scanner Logic (
violetear.markup)We need a reliable way to traverse the Violetear component tree and extract all class names referenced by the elements.
1.1
Element.scan_classes()self.classesfrom the element and all its children.Set[str]to ensure uniqueness.(Note: Basic implementation already exists in the current codebase, but needs to be formalized and tested against
Componentsubclasses).1.2
Document.get_used_classes()2. Filter Logic (
violetear.stylesheet)The
StyleSheetclass needs a new rendering mode that accepts a filter.2.1
StyleSheet.render_subset(used_classes: Set[str]) -> strStyleobjects.Selectorof each style.body,h1), always include (global styles).#header), always include (specific styles)..btn.primary):used_classes..btn.primaryis kept only if bothbtnandprimaryare used.@keyframesanimation, that animation definition must also be included in the output.3. Server-Side Integration (
violetear.app.App)The
Appclass handles the request/response lifecycle and decides how to serve the CSS.3.1 Routing Logic Update
We will update the
routewrapper to support a mode switch (e.g.,jit=Trueor default behavior for non-PWA routes).Workflow:
Document.doc.get_used_classes()to get the set of active tokens.doc.head.styles.StyleSheetobject (not a string URL):sheet.render_subset(used_classes).<link>tag in the header with a<style>tag containing the optimized CSS string.3.2 Caching Considerations (Future)
used_classesset to avoid re-filtering the stylesheet on every request.4. Usage Example
No changes required in user code! The optimization happens transparently.
5. Task List
render_subsetmethod toStyleSheet.render_subsetcorrectly handles dependency resolution (e.g., styles using@keyframes).App.routeto perform the scan-and-inline process forDocumentresponses.