Hi everyone ( first post on a forum, sorry for mistakes ), I'm building a library for handle my custom design system logic; I've searched a lot but it seems like a tailwind limitation, I have many components like TypographyDisplay that has props like size or fontColor that needs to be dynamically rendered basing on how the component is instantiated. I'm using Qwik framework but I found that problem in Next.JS too and I'm going to have a terrible headhache: I don't want to send all the class possibile combination in the css bundle, if I instantiate like this "<TypographyDisplay fontColor = "primary">Something</TypographyDisplay>" i only want to send .text-primary not all the theme fontColor combinations in bundle :( I'm using SSR to avoid those things, I've seen that I can purge files but I don't know how to purge SSR generated HTML...Qwik is also a resumable framework so it sends pure HTML to client, I find that TailwindCSS behaviour so frustrating, it should simply understand what class are going to be rendered in that occasion and make bundle on-the-fly...is not the JIT mode (that should be used as default) do something like this? Have I to switch to another CSS technology or use some meta-utils like twin.macro? thanks for the time spent.
package.json
{
"name": "my-qwik-basic-starter",
"description": "App with Routing built-in (recommended)",
"engines": {
"node": ">=15.0.0"
},
"private": true,
"scripts": {
"build": "qwik build",
"build.client": "vite build",
"build.preview": "vite build --ssr src/entry.preview.tsx",
"build.types": "tsc --incremental --noEmit",
"deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'",
"dev": "vite --mode ssr",
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
"fmt": "prettier --write .",
"fmt.check": "prettier --check .",
"lint": "eslint \"src/**/*.ts*\"",
"preview": "qwik build preview && vite preview --host",
"start": "vite --host --mode ssr",
"qwik": "qwik"
},
"devDependencies": {
"@builder.io/qwik": "0.17.5",
"@builder.io/qwik-city": "0.1.0",
"@types/eslint": "8.21.0",
"@types/node": "^18.11.19",
"@types/node-fetch": "latest",
"@typescript-eslint/eslint-plugin": "5.51.0",
"@typescript-eslint/parser": "5.51.0",
"autoprefixer": "10.4.11",
"eslint": "8.33.0",
"eslint-plugin-qwik": "0.17.5",
"node-fetch": "3.3.0",
"postcss": "^8.4.16",
"prettier": "2.8.3",
"tailwindcss": "^3.1.8",
"typescript": "4.9.5",
"undici": "5.18.0",
"vite": "4.1.1",
"vite-tsconfig-paths": "3.5.0"
},
"dependencies": {
"@builder.io/sdk-qwik": "^0.1.7",
"dotenv": "^16.0.3"
}
}
tailwind.config.js
/** @type {import('tailwindcss').Config} */
const MDSysTypefaceDisplayLarge = require( "./src/designTokens/materialDesign/md.sys.typescale.display-large" ) ;
const MDSysTypefaceDisplayMedium = require( "./src/designTokens/materialDesign/md.sys.typescale.display-medium" ) ;
const MDSysTypefaceDisplaySmall = require( "./src/designTokens/materialDesign/md.sys.typescale.display-small" ) ;
// etc.
module.exports = {
content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
theme: {
fontFamily : {
"display-large" : MDSysTypefaceDisplayLarge.font ,
"display-medium" : MDSysTypefaceDisplayMedium.font ,
"display-small" : MDSysTypefaceDisplaySmall.font ,
// etc.
} ,
fontSize : {
"display-large" : [ MDSysTypefaceDisplayLarge.size + "px" , {
lineHeight : MDSysTypefaceDisplayLarge.lineHeight + "px" ,
letterSpacing : MDSysTypefaceDisplayLarge.tracking + "px" ,
fontWeight : MDSysTypefaceDisplayLarge.weight
} ] ,
"display-medium" : [ MDSysTypefaceDisplayMedium.size + "px" , {
lineHeight : MDSysTypefaceDisplayMedium.lineHeight + "px" ,
letterSpacing : MDSysTypefaceDisplayMedium.tracking + "px" ,
fontWeight : MDSysTypefaceDisplayMedium.weight
} ] ,
"display-small" : [ MDSysTypefaceDisplaySmall.size + "px" , {
lineHeight : MDSysTypefaceDisplaySmall.lineHeight + "px" ,
letterSpacing : MDSysTypefaceDisplaySmall.tracking + "px" ,
fontWeight : MDSysTypefaceDisplaySmall.weight
} ] ,
// etc.
} ,
extend: {},
},
plugins: [],
};
UITypographyHeadingDisplay.tailwindcss.ts
import type { IUITypographyHeadingDisplay } from "../.." ;
import { EUIComponentColors, EUIComponentSizes } from "~/components/enums" ;
import { UITypographyHeadingTailwindCSSStylingStrategyHandler } from "~/components/ui/typography/headings" ;
export interface IUITypographyHeadingDisplayTailwindCSSStylingStrategyProps extends IUITypographyHeadingDisplay {}
export type IUITypographyTailwindCSSStylingStrategy = ( args : IUITypographyHeadingDisplayTailwindCSSStylingStrategyProps ) => string[] ;
export const UITypographyHeadingDisplayTailwindCSSStylingStrategyHandler : IUITypographyTailwindCSSStylingStrategy = ( {
size = EUIComponentSizes.MEDIUM ,
fontColor = EUIComponentColors.ON_SURFACE ,
isBold = false ,
isItalic = false ,
} ) => {
let _classNames : string[] = UITypographyHeadingTailwindCSSStylingStrategyHandler( {
fontColor ,
isBold ,
isItalic ,
} ) ;
const fontFaceClassName =
size === EUIComponentSizes.LARGE ? "font-display-large" :
size === EUIComponentSizes.MEDIUM ? "font-display-medium" :
size === EUIComponentSizes.SMALL ? "font-display-small" :
""
;
;
if ( fontFaceClassName !== "" ) _classNames = [
..._classNames ,
fontFaceClassName ,
] ;
const fontSizeClassName =
size === EUIComponentSizes.LARGE ? "text-display-large" :
size === EUIComponentSizes.MEDIUM ? "text-display-medium" :
size === EUIComponentSizes.SMALL ? "text-display-small" :
""
;
if ( fontSizeClassName !== "" ) _classNames = [
..._classNames ,
fontSizeClassName
] ;
return _classNames ;
} ;
UITypographyDisplay.tsx
import { component$ } from "@builder.io/qwik" ;
import type { IUITypographyHeadingDisplay } from "../" ;
import { UITypographyHeadingDisplayTailwindCSSStylingStrategyHandler } from "../" ;
import { QwikHTMLTypographyHeading } from "~/components/html/typography/concretes/heading" ;
import { QwikHTMLTypographyBoldDecorator } from "~/components/html/typography/decorators/bold" ;
import { QwikHTMLTypographyItalicDecorator } from "~/components/html/typography/decorators/italic" ;
import {
EUIComponentSizes ,
EUIComponentColors ,
} from "~/components/enums" ;
import { EUITypographyHeadingLevels } from "~/components/enums/typography/headings" ;
export interface IUITypographyHeadingDisplayQwikComponentProps extends IUITypographyHeadingDisplay {}
export const QwikUITypographyHeadingDisplay = component$( ( {
id = undefined ,
onClick = undefined ,
onChange = undefined ,
size = EUIComponentSizes.MEDIUM ,
fontColor = EUIComponentColors.ON_SURFACE ,
isBold = false ,
isItalic = false ,
HeadingLevel = EUITypographyHeadingLevels.H1 ,
copy = "" ,
} : IUITypographyHeadingDisplayQwikComponentProps ) => {
const _classNames = UITypographyHeadingDisplayTailwindCSSStylingStrategyHandler( {
size ,
fontColor ,
isBold ,
isItalic
} ) ;
const _QwikHTMLTypographyHeadingProps = {
id ,
onClick ,
onChange ,
classNames : _classNames.join( " " ) ,
HeadingLevel ,
} ;
return (
<QwikHTMLTypographyBoldDecorator isBold = { isBold } >
<QwikHTMLTypographyItalicDecorator isItalic = { isItalic } >
<QwikHTMLTypographyHeading { ..._QwikHTMLTypographyHeadingProps } >
{ copy }
</QwikHTMLTypographyHeading>
</QwikHTMLTypographyItalicDecorator>
</QwikHTMLTypographyBoldDecorator>
) ;
} ) ;
QwikHTMLTypographyHeading
import {
component$ ,
Slot ,
} from "@builder.io/qwik" ;
import type { IHTMLTypographyHeading } from ".." ;
import { EUITypographyHeadingLevels } from "~/components/enums/typography/headings" ;
export interface IHTMLTypographyHeadingQwikComponentProps extends IHTMLTypographyHeading {}
export const QwikHTMLTypographyHeading = component$( ( {
classNames = undefined ,
HeadingLevel = EUITypographyHeadingLevels.H1 ,
} : IHTMLTypographyHeadingQwikComponentProps ) => {
return (
<HeadingLevel class = { classNames } >
<Slot />
</HeadingLevel>
) ;
} ) ;
tried to set mode:"jit" but obv nothing changes
class = text-${color}
was the first attempt and obv not working without commenting classnames or adding them to safelist, far i've understand to use full classnames but laaarge bundle size if someone use a complex design system
ps: I've tried to extrapolate classNames into an external object and that object in an external file too and accessing it like colorStyles[color] but same result with dirty enumerator usage, I've tried to put the logic into QwikHTMLTypographyHeading class property but same result...
I want only to compile css classes with ssr pros like knowing the classname of a used component to have correct bundle size...