43081j / postcss-lit

PostCSS syntax for extracting CSS from template literals inside JS/TS files

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Can you provide a working example of postcss-lit with tailwindcss?

flipkickmedia opened this issue · comments

commented

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.

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: #23 (comment)

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/**/*...

  1. Let's say that you wanted to build 25 small chunks of js corresponding to 25 separate small web components that could be lazy loaded.
  2. Let's also say that html in web component 1 just contains px-1, component 2 contains px-2, component 3 contains px-3...

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.

  • Imagine if you had a project that used most of the features in Tailwind across hundreds of components, and each individual component ended up being giant because of duplicated css from Tailwind that wasn't purged.

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.

  • It would be handy to have a Tailwind css purger that ran independently for each web component across all components in a project. Perhaps a custom build script could run Tailwind once for each individual component, so that it purged all css not used in that component.

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:

  1. Use Tailwind CSS only inside of html in Lit components, and prefer to do most styling that way.
  2. If you need to write custom css, stick it in an external css file that's processed with PostCSS and autoprefixer, and import it into your Lit component.

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.