-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
-
I am trying to use Tailwind 4 in my backend code to create dynamic results. Unfortunately I cant make it work, this is what I go so far:
import tailwindcss from '@tailwindcss/postcss'; import autoprefixer from 'autoprefixer'; const postcssResult = await postcss([ tailwindcss({ content: [{ raw: "<div class='text-red-500 font-bold'>Hello</div>" }] }), autoprefixer(), ]).process(`@import "tailwindcss"`, { from: undefined, }); return postcssResult.css;
For content
it tells me content does not exist in type PluginOptions
but the bigger problem is it throws an error because it cant find the css @import "tailwindcss"
:
Can't resolve 'tailwindcss'
Stackblitz: https://stackblitz.com/edit/github-u6vrxc-dfzdtw4o?file=routes%2Findex.ts
Beta Was this translation helpful? Give feedback.
All reactions
Replies: 5 comments 9 replies
-
You may need to set base
and from
properly, see #16097 (comment).
However, @tailwindcss/postcss
is file-system based which means you would need to create a temporary file for the raw content and have Tailwind scan that. Otherwise, you could try to adapt the code in @tailwindcss/vite
for your needs (since that does not run Tailwind in a file-based way).
Beta Was this translation helpful? Give feedback.
All reactions
-
You can probably just use tailwindcss
or maybe @tailwindcss/node
if you are willing to mess around with the internal/undocumented/not public APIs we use for everything.
Some code to poke around at:
Beta Was this translation helpful? Give feedback.
All reactions
-
Hi @adamwathan , did anything change since february? Is there maybe now a way to compile programmatically? Or maybe are this internal apis now documented?
Beta Was this translation helpful? Give feedback.
All reactions
-
A typical use case I came across multiple times now: In my Backend (H3/Nitro) I want to render a Mail or PDF template as html. For this I can use Vue which renders the html as a string. For the styles I would love to use Tailwind, but it would require that I have a function (that hopefully works not just in Node, but also other environments like serverless, Deno, Bun, etc) and accepts and input (either the imported vue file or the generated html string) without use of the filesystem. This function would return the styles as a string, optionally minified etc.
With Tailwind 3 this was possible, but with Tailwind 4 I cant find the right config. I assume using post-css is the key again but I couldt make it ...
Beta Was this translation helpful? Give feedback.
All reactions
-
👍 1
-
Hey @MickL, did you find a solution? I'm looking for the same thing after upgrading to v4. Thanks!
Beta Was this translation helpful? Give feedback.
All reactions
-
Did you find out anything?
Beta Was this translation helpful? Give feedback.
All reactions
-
I found a solution, I hope it works for you too.
You have to use something like jsdom or parse5 to parse your html and extract all classnames, and end with an array like this:
["bg-gray-50","p-6","rounded-lg","shadow-md","text-center","bg-[#f29101]","flex","h-16","items-center","justify-center","mb-4","mx-auto","rounded-full","w-16","h-8","text-black","w-8","font-semibold","mb-2","text-gray-900","text-xl","text-gray-600"]
Then you just need to install tailwindcss
dependency, no need for postcss, and build a compiler like this:
import { compile } from "tailwindcss"; const tailwindCompiler = await compile('@import "tailwindcss";', { loadStylesheet: async (id: string, base: string) => { if (id === "tailwindcss") { return { path: "virtual:tailwindcss/index.css", base, // try to find more elegant ways of loading tailwind index.css depending on your bundler content: await readFile( "node_modules/tailwindcss/index.css", "utf-8", ), }; } throw new Error(`can't load stylesheet id:${id} base:${base}`); }, });
Then you compile passing our previous list of classes, like this:
tailwindCompiler.build(["bg-gray-50","p-6","rounded-lg","shadow-md","text-center","bg-[#f29101]","flex","h-16","items-center","justify-center","mb-4","mx-auto","rounded-full","w-16","h-8","text-black","w-8","font-semibold","mb-2","text-gray-900","text-xl","text-gray-600"])
And thats it 😄
Beta Was this translation helpful? Give feedback.
All reactions
-
Thanks this might be something! Just wanted to add that postcss is needed to run autoprefixer and minification after tailwind
Beta Was this translation helpful? Give feedback.
All reactions
-
I think autoprefixer is not longer needed in v4
Beta Was this translation helpful? Give feedback.
All reactions
-
Why max autopefixer no longer needed?
I found react-email using Tailwind 4 and they also use the compile()
function. But what they do is they scan all of their dom elements and then add all used classes manually. Posted the links below in another answer.
Beta Was this translation helpful? Give feedback.
All reactions
-
I solved this by adding the following line to my global css file
@source "../src/**/*.{astro,html,js,jsx,ts,tsx}"
Beta Was this translation helpful? Give feedback.
All reactions
-
How does this help in a JavasScript file?
Beta Was this translation helpful? Give feedback.
All reactions
-
@adamwathan Did anything change over the course of this year? May we have capabilities to use Tailwind programmatically now or is it better documented?
This is my current solution, it works:
import { compile } from 'tailwindcss'; import tailwindStyles from 'tailwindcss/index.css?raw'; let compiler: { build(candidates: string[]): string }; export async function useTailwind(html: string, styles = '@import "tailwindcss";'): Promise<string> { if (!compiler) { compiler = await compile(styles, { loadStylesheet: async (id: string, base: string) => { if (id === 'tailwindcss') { return { path: 'virtual:tailwindcss/index.css', base, content: tailwindStyles, }; } throw new Error(`can't load stylesheet id:${id} base:${base}`); }, }); } const classes = Array.from(html.matchAll(/class\s*=\s*("|')(.*?)1円/g), (m) => m[2]) .flatMap((s) => s.split(/\s+/)) .filter(Boolean); return compiler.build(classes); }
Beta Was this translation helpful? Give feedback.