web-ui: fix wave-1 build pipeline (primitives missing from bundle)

Three bugs found during task 20 verify, all fixed:

1. Tailwind CLI does NOT read postcss.config.js. Switched Dockerfile to
   npx postcss + postcss-cli so the postcss plugin chain actually runs.

2. postcss-import was not installed but app.css uses @import for the
   primitive component files. Added postcss-import + cssnano (for prod
   minification under --env production).

3. @import statements must come BEFORE any other rules per CSS spec.
   app.css had @tailwind base/components ABOVE @import, so postcss-import
   silently skipped every component @import. Moved all @imports to the
   top, @tailwind directives below. Bundle went from 121KB with 0 wd-*
   classes to 138KB with 116 wd-* classes.

Also added tailwind safelist for wd-/is-/nav-dev-badge so the wave-2
migration of HTML files cannot accidentally tree-shake primitives.
This commit is contained in:
Zac Gaetano 2026-05-21 16:41:55 +00:00
parent f9236101b9
commit 3b89cf2d5f
5 changed files with 26 additions and 23 deletions

View file

@ -12,7 +12,7 @@ COPY src/ ./src/
COPY public/ ./public/ COPY public/ ./public/
# Build into public/dist/app.css # Build into public/dist/app.css
RUN npx tailwindcss -i ./src/css/app.css -o ./public/dist/app.css --minify RUN npx postcss ./src/css/app.css -o ./public/dist/app.css --env production
# Stage 2: runtime # Stage 2: runtime
FROM nginx:alpine FROM nginx:alpine

View file

@ -4,12 +4,15 @@
"private": true, "private": true,
"description": "Build-time-only deps for the Wild Dragon web-ui Tailwind/flyon-ui pipeline. Not shipped at runtime.", "description": "Build-time-only deps for the Wild Dragon web-ui Tailwind/flyon-ui pipeline. Not shipped at runtime.",
"scripts": { "scripts": {
"build:css": "tailwindcss -i ./src/css/app.css -o ./public/dist/app.css --minify" "build:css": "postcss ./src/css/app.css -o ./public/dist/app.css --env production"
}, },
"devDependencies": { "devDependencies": {
"tailwindcss": "^3.4.0", "tailwindcss": "^3.4.0",
"postcss": "^8.4.35", "postcss": "^8.4.35",
"autoprefixer": "^10.4.17", "autoprefixer": "^10.4.17",
"flyonui": "^1.0.0" "flyonui": "^1.0.0",
"postcss-import": "^16.0.0",
"postcss-cli": "^11.0.0",
"cssnano": "^7.0.0"
} }
} }

View file

@ -1,6 +1,8 @@
module.exports = { module.exports = ({ env }) => ({
plugins: { plugins: {
'postcss-import': {},
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
...(env === 'production' ? { cssnano: { preset: 'default' } } : {}),
}, },
}; });

View file

@ -1,20 +1,12 @@
/* app.css Tailwind directives + primitive imports. /* app.css Tailwind directives + primitive imports.
* *
* Order matters: * IMPORTANT: All @import must come first per CSS spec / postcss-import
* 1. tokens (CSS custom properties for legacy callers) * requirements. Tailwind directives below; cascade order in the emitted
* 2. tailwind base (CSS reset) * bundle is: tokens primitives tailwind base tailwind components
* 3. tailwind components * tailwind utilities. Utilities win on specificity, primitives win
* 4. our primitives (use tokens + can be overridden by utilities) * over base where they share specificity.
* 5. tailwind utilities (highest specificity, last word)
* 6. motion (animations + reduced-motion override)
*/ */
@import "./components/tokens.css"; @import "./components/tokens.css";
@tailwind base;
@tailwind components;
/* Primitives — each one ~50-200 lines, one responsibility per file */
@import "./components/sidebar.css"; @import "./components/sidebar.css";
@import "./components/topbar.css"; @import "./components/topbar.css";
@import "./components/button.css"; @import "./components/button.css";
@ -27,12 +19,13 @@
@import "./components/empty-state.css"; @import "./components/empty-state.css";
@import "./components/badge.css"; @import "./components/badge.css";
@import "./components/toast.css"; @import "./components/toast.css";
@tailwind utilities;
@import "./components/motion.css"; @import "./components/motion.css";
/* Global base — self-hosted fonts */ @tailwind base;
@tailwind components;
@tailwind utilities;
/* Self-hosted fonts */
@font-face { @font-face {
font-family: 'Inter'; font-family: 'Inter';
src: url('/fonts/inter-400.woff2') format('woff2'); src: url('/fonts/inter-400.woff2') format('woff2');

View file

@ -4,6 +4,11 @@ module.exports = {
'./public/**/*.html', './public/**/*.html',
'./src/**/*.{css,js}', './src/**/*.{css,js}',
], ],
safelist: [
{ pattern: /^wd-/ },
{ pattern: /^is-/ },
'nav-dev-badge',
],
darkMode: 'class', darkMode: 'class',
theme: { theme: {
extend: { extend: {