tailwind2-8 Exercise 2: Finish by Hand to Zero Pixels, and Test the Safelist =============================================================================== Start from the project after the upgrade tool (exercise 1). Delete tailwind.config.js, replace src/input.css, edit three lines of index.html, rebuild, screenshot and compare with the v3 baseline. --- src/input.css --- @import 'tailwindcss'; @plugin '@tailwindcss/typography'; @source inline("bg-{emerald,pink}-500"); @custom-variant dark (&:is(.dark *)); @theme { --color-brand-500: #4f46e5; --color-brand-600: #4338ca; --color-surface: #f1f5f9; --font-display: Georgia, serif; --breakpoint-3xl: 1920px; --radius-card: 0.75rem; } @layer base { *, ::after, ::before, ::backdrop, ::file-selector-button { border-color: var(--color-gray-200, currentcolor); } h1 { @apply text-2xl font-bold; } } @utility btn { @apply inline-flex items-center rounded-md bg-brand-500 px-4 py-2 text-sm font-medium text-white hover:bg-brand-600 focus:outline-hidden focus:ring-2; } @utility panel { background: var(--color-surface); border-radius: var(--radius-card); padding: --spacing(4); } --- index.html changes ---
safelisted + transform
node node_modules/@tailwindcss/cli/dist/index.mjs -i src/input.css -o dist/out.css Done in 330ms, exit 0 node pix.mjs v3.png up2.png diff2.png -> v3.png vs up2.png differing pixels 0 of 490000 --- dark.mjs --- import { withPage } from './../c4/cdp.mjs'; const d=process.argv[2]; await withPage(`file:///C:/lwdj/tw2/c8/${d}/index.html`, async (p) => { console.log(d,'body bg light:', await p.css('body','background-color')); await p.ev(`document.documentElement.classList.add('dark')`); console.log(d,'body bg with :', await p.css('body','background-color')); }); node dark.mjs proj -> body bg light rgb(255,255,255) ; with rgb(15,23,42) node dark.mjs up2 -> body bg light rgb(255,255,255) ; with oklch(0.208 0.042 265.755) (the same slate-900) grep -c '\.bg-pink-500' dist/out.css -> 1 (from @source inline) Safelist test, v3 config with safelist: ['bg-emerald-500','bg-pink-500'] (bg-pink-500 appears nowhere in the markup): v4 build with @config still loading the file: bg-pink-500 rule present (1) LOOKS like safelist works rewrite the entry as 'bg-pink-' + '500' v4: 0 rules v3 (same config): 1 rule The scanner had found the literal 'bg-pink-500' in tailwind.config.js itself; the safelist option was never read. WHY THIS WORKS AS AN ANSWER --------------------------- Each setting in the JavaScript config has a CSS home, and once all are moved the page is pixel-identical (0 of 490,000 pixels), including dark mode (@custom-variant dark with the .dark class) and the typography plugin (@plugin). The three markup edits are the ones the tool could not decide for you: bg-black/50 replaces the removed opacity utility, ring-3 ring-blue-500/50 restores the old ring colour, and scale-105 no longer needs transform. The safelist test shows why a "works" result can be a coincidence: in v4 the file scanner sees ANY text file, including the config, so a literal class name written in a safelist is generated as if it were used. Concatenating the string hides it from the scanner and shows the truth: safelist is ignored, matching Tailwind's guide ("corePlugins, safelist, and separator ... are not supported in v4.0"). Use @source inline("bg-{emerald,pink}-500").