Open flipkickmedia opened 8 months ago
After failing to get postcss-lit working with rollup to transform css within static styles = css`` (which vite uses in case that's relevant), I have also come to the conclusion in this comment: https://github.com/43081j/postcss-lit/issues/23#issuecomment-1848389575
As a side note, I think there might be a fundamental problem with using Tailwind CSS with web components or Lit. In a typical tailwind.config.js file, you manage css purging with content: ['./src/*/...
What you'll find when you look in the bundled file for a component, is that its css contains px-1, px-2, px-3... even though the component is only using one of those classes in its html.
If we just bundle all components into one js bundle and share the Tailwind css to prevent deploying duplicate Tailwind css, then we aren't taking advantage of the scalable nature of lazy loading many small independent web components.
After thinking about things, if it's hard to use PostCSS syntax inside of a Lit file, it might also be hard to purge Tailwind css for similar reasons. It seems like just using PostCSS (not Tailwind, so no purging) in css files imported into Lit components makes the most sense for now.
I got inspired by: https://github.com/mwmcode/rollup-plugin-lit-tailwindcss/blob/main/src/index.js
ChatGPT helped me come up with the following simple concept.
vite.config.ts:
import postcss from 'postcss'
import tailwindcss from 'tailwindcss'
import { defineConfig } from 'vite'
import tsconfigPaths from 'vite-tsconfig-paths'
function viteLitTailwind() {
return {
name: 'vite-lit-tailwind',
async transform(code, id) {
if (!id.endsWith('.ts')) return null
const match = code.match(/css`([\s\S]*?@tailwind\s+\w+;[\s\S]*?)`/)
if (match) {
try {
const result = await postcss([
tailwindcss({
content: [id]
})
]).process(match[1], { from: undefined, to: undefined })
if (result.css) {
return code.replace(match[0], `css\`${result.css.replace(/`/g, '\\`')}\``)
}
} catch (error) {
this.error('Error processing with Tailwind CSS: ', error)
}
}
return null
}
}
}
export default defineConfig({
plugins: [tsconfigPaths(), viteLitTailwind()]
})
lit-web-component.ts:
render() {
return html`
<p class="px-2">Hello World</p>
`
}
static styles = css`
@tailwind utilities;
`
It runs tailwindcss for each Lit component that contains a Tailwind directive (ex. @tailwind utilities;
) in its first css``, passing in the TypeScript filename (ex. lit-web-component.ts) for purging based on just that file alone. In order to keep components light, it probably makes sense to abandon @tailwind
base and components directives and only use utilities, to keep css to a minimum in each component. Since the vite plugin code is simple, you can keep adding more functionality whenever you run into a bug or limitation.
Here's how I could imagine using this:
in the projects i've used tailwind in, we basically split the styles out in all non-trivial cases
i.e. we have this:
// my-element.ts
class MyElement extends LitElement {
static styles = [commonStyles];
}
// my-other-element.ts
class MyOtherElement extends LitElement {
static styles = [
commonStyles,
css`some local styles that don't use tailwind`
];
}
// common-styles.ts
export const commonStyles = css`
/* some tailwind mixins */
`;
the point being to share stylesheets across elements often. although tbh we have mostly moved into css files now
in the projects i've used tailwind in, we basically split the styles out in all non-trivial cases
i.e. we have this:
// my-element.ts class MyElement extends LitElement { static styles = [commonStyles]; } // my-other-element.ts class MyOtherElement extends LitElement { static styles = [ commonStyles, css`some local styles that don't use tailwind` ]; } // common-styles.ts export const commonStyles = css` /* some tailwind mixins */ `;
the point being to share stylesheets across elements often. although tbh we have mostly moved into css files now
Regarding just Tailwind though, you either have the Tailwind directives (ex. @tailwind/utilities;
) mentioned once in your code base and use a purging glob like content: ['./src/**/*.ts']
and end up with a large amount of Tailwind css swapped out in place of that single @tailwind/utilities;
which is shared by all components, or you actually put @tailwind/utilities;
inside many components and have a purging glob like content: ['./src/lit-web-component.ts']
swap out just the Tailwind css used in that glob. I think if someone was going to have 1,000 components and use lazy loading, eventually they might find that the shared Tailwind css swapped out in place of their single @tailwind/utilities;
was large, and their initial page load for the entry point would take longer to load, which is similar to the situation we are in currently with front-end monoliths.
Ive been trying to get tailwindcss working with lit and postcss-lit seems to offer a way to be able to do this but the examples on the internet fail for me.
If you could show an example of how to get this setup Id appreciate it.