Poimen / stencil-tailwind-plugin

Plugin for using tailwindcss with StencilJS
https://www.npmjs.com/package/stencil-tailwind-plugin
MIT License
51 stars 5 forks source link

Support for TailwindCSS 3.0.0 #11

Closed eswat2 closed 2 years ago

eswat2 commented 2 years ago

i tried to rebuild my apps with this using the latest TailwindCSS 3.0.0 release, but it appears that requires changes to this plugin. I tried to update this plugin locally, but i haven't been successful in getting something that runs...

Poimen commented 2 years ago

Oh wow, didn't realise v3 was out 😄

Will have a look - the alpha version release notes didn't seem to indicate any real concerning points, so could be that JIT has changed, or purge (they changed the way purge was handled with JIT introduction).

Thanks for the heads up

eswat2 commented 2 years ago

I couldn't get the stencil-tailwind-plugin to work with Tailwind 3.0, so I refactored my apps to use the new Tailwind CLI. I can also now support deeply nested functional components, all of that styling rolls up into the parent Web Component.

The configuration may need some refinement, but it currently works and has been used to deploy both of my Stencil/Tailwind test beds...

Poimen commented 2 years ago

That's interesting - do you have a repo for that?

It could be that with v3 CLI you may not need the plugin at all 🎉 I wouldn't be sad if that was the case, using standard tooling is always a win 😃

I haven't even tried the CLI, so thanks for the pointers

dtaalbers commented 2 years ago

I couldn't get the stencil-tailwind-plugin to work with Tailwind 3.0, so I refactored my apps to use the new Tailwind CLI. I

Would also like to see how that is set up!

Poimen commented 2 years ago

@eswat2 I'm intrigued if your solution targets a single output css, or actually outputs css per component?

Poimen commented 2 years ago

@eswat2 I have just updated my example repo at: https://github.com/Poimen/stencil-tailwind-plugin-example

It runs Tailwind 3.0 with the warning:

[17:03.3]  copy finished (0 files) in 37 ms

warn - The `purge`/`content` options have changed in Tailwind CSS v3.0.
warn - Update your configuration file to eliminate this warning.

But this works as expected... 🤔

I did a quick update to remove the warning, and works without a warning. I'm going to do some more tests, but so far can't see any misbehaving...

Is it possible for you to reproduce this on the example repo?

Poimen commented 2 years ago

I have pushed up a branch next with the updates for Tailwind v3. I have also released v1 under the tag next on npm.

The example repo is using those new components, but so far I haven't seen anything break, unfortunately.

I haven't tried this yet on our big repo of components as we're currently under a shutdown freeze, so don't have resources until next year to work on that. Hopefully can reproduce the error on the example repo 🙏

eswat2 commented 2 years ago

ok, i don't have a public repo with my CLI solution yet, but in a nutshell i wrote a set of scripts which use the CLI to generate the file pointed to in styleUrl in the @Component definition. In my Sudoku app, i only have two formal Components, everything else is a FunctionalComponent. So i run the CLI twice to generate the appropriate styleUrl files. Each of those setups has an independent input file that contains the typical @tailwind stuff, with any custom css or definitions required for that component.

In development, i can run both pipelines using the CLI with a --watch flag and get Tailwind to dynamically update the styling on the fly.

For production, i run those same CLI setups with a --minify flag before i do the final build.

It took a bit to figure out the setup, but it works pretty well. The added benefit as i mentioned before is that this will handle deeply nested functional components and it just rolls all the styling into the parent Component. One of the other advantages of this approach is that you can see all the styling that's being generated while in development. I was running a ksdiff between the 2 styleUrl files to see how things were being exported from Tailwind.

i'll try to create a public repo with this approach and let you know here...

ps. i'll try the next branch on one of my examples and let you know how that goes...

eswat2 commented 2 years ago

one CAVEAT with my approach, for this to work the functional components need to be in the same directory as the parent Component. This wasn't a problem with my Sudoku app because that's how i'd organized the files. YMMV

eswat2 commented 2 years ago

actually, as soon as i say that i realize you could just update the content in the tailwind configs to pull in functional components that live in separate directories...

eswat2 commented 2 years ago

Here's one of the .generate scripts that i use in my Sudoku app:

#!/bin/bash
CONFIG=./.tailwind.config.js
STYLES=../../styles/app.pcss
OUTPUT=./proto-sudoku.css

if [ -f $CONFIG ]
then
  if [ -f $STYLES ]
  then
    echo '-- proto-sudoku'
    npx tailwindcss -c $CONFIG -i $STYLES -o $OUTPUT $1
  fi
fi

i have independent .tailwind.config.js and input files for each Component and that gives the me the flexibility to tailor the CLI for each parent component...

for development, i can pass the --watch flag to this script for production, i pass the --minify flag to this script

eswat2 commented 2 years ago

that script is really the workhorse behind this approach...

eswat2 commented 2 years ago

here's the .tailwind.config.js from that example:

const plugin = require('tailwindcss/plugin');
const tw_clrs = require('proto-tailwindcss-clrs');

module.exports = {
  content: ['./*.tsx'],
  corePlugins: {
    preflight: false,
  },
  theme: {
    extend: {
      spacing: {
        '24px': '24px',
        '76p5': '19.125rem',
      },
    },
  },
  variants: {},
  plugins: [
    tw_clrs({
      map: {
        bada55: '#bada55',
        slate: '#708090',
        slate4: '#4e5964',
        white: '#ffffff',
      },
      alphas: [50],
    }),
    plugin(function ({ addUtilities, theme, config }) {
      const themeColors = theme('colors');
      const individualColoredBorders = Object.keys(themeColors).map(
        colorName => ({
          [`.border-xbb-${colorName}`]: {
            borderBottom: `1px solid ${themeColors[colorName]} !important`,
          },
          [`.border-xbt-${colorName}`]: {
            borderTop: `1px solid ${themeColors[colorName]} !important`,
          },
          [`.border-xbl-${colorName}`]: {
            borderLeft: `1px solid ${themeColors[colorName]} !important`,
          },
          [`.border-xbr-${colorName}`]: {
            borderRight: `1px solid ${themeColors[colorName]} !important`,
          },
        }),
      );

      addUtilities(individualColoredBorders);
    }),
  ],
};

You'll notice that i'm restricting the content to the local tsx files, which include the parent component and all the functional components used by it.

There's more here than you might typically see since i'm using a few plugins to extend Tailwind...

eswat2 commented 2 years ago

and here's the app.pcss used in this example:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer components {
  .ds1-main {
    @apply flex flex-col m-6 text-clrs-navy font-sans antialiased;
  }
}

this file serves as the INPUT to the CLI, so i can put custom definitions in this file for that specific component (in this case proto-sudoku)

eswat2 commented 2 years ago

the actual component is here:

import { Component, h, Prop } from '@stencil/core';
import { Alerts } from './alerts';
import { Eswat2Io } from './eswat2-io';
import { Header } from './header';
import { ToolBar, Keys } from './tool-bar';
import { actions } from '../../utils';

@Component({
  tag: 'proto-sudoku',
  styleUrl: 'proto-sudoku.css',
  shadow: true,
})
export class ProtoSudoku {
  @Prop() tag: string = 'proto-sudoku';

  componentDidLoad() {
    actions.initApp();
  }

  render() {
    return (
      <div id="app" class="ds1-main p-0.5 max-w-min relative">
        <Eswat2Io />
        <Header>Sudoku</Header>
        <sudoku-board />
        <Keys />
        <hr class="ml-0 mr-0" />
        <ToolBar />
        <Alerts />
      </div>
    );
  }
}

The Tailwind CLI is generating the proto-sudoku.css file and Stencil is updating when it's changed.

The sub-components are all FunctionalComponents that get imported. Some of these are built on other FunctionalComponents, thus the need to support deeply nested functional components...

eswat2 commented 2 years ago

Hope that helps explain my approach. Like i said, i think there's room for improvement but it seems to work fairly well for the smaller projects that i have. Both of these were built with this approach:

https://wc-autos.vercel.app https://wc-sudoku.vercel.app

eswat2 commented 2 years ago

thinking about this some more, i could probably create a script which could generate the .tailwind.config.js files from a TEMPLATE, making it easier to support any number of Components you might define. For now, i'll probably stick with the manual approach of setting this up...

eswat2 commented 2 years ago

oh, one other thing, i added another .generate script to the top of the project so i can reference it from my package.json and generate all of the css using yarn

#!/bin/bash
CODE=./src/components
GEN=.generate
SRC=(
  proto-sudoku
  sudoku-board
)

if [ -d $CODE ]
then
  cd $CODE
  for pak in "${SRC[@]}"
  do
    if [ -d $pak ]
    then
      cd $pak
      if [ -f $GEN ]
      then
        bash $GEN $1
      fi
      cd ..
    fi
  done
fi

it's setup so that i can pass a flag thru to the component specific .generate scripts

still need to get this working for --watch from the top-level, but it does what i need for now...

Poimen commented 2 years ago

@eswat2 thanks for the details, it makes sense. I had thought there must be some scripting going on.

I also had a thought this morning that my approach may be to change this to modify the CSS dependencies rather than the tsx, but there was a reason why I went that route. I just can't remember.

Had another thought of moving this to a rollup before plugin so that it can mix the CSS and content.

Did you get a chance to try the pre-release at all?

eswat2 commented 2 years ago

Not yet, maybe this weekend...

eswat2 commented 2 years ago

for a simple case with only one Component (and a bunch of functional components), there's really no scripting, you just call the Tailwind CLI to generate the styleUrl file and you're done. But this becomes more complicated if you are publishing a bunch of Components, that's where the plugin approach makes more sense.

We're building feature Components, so we tend to have a single top-level Component with a bunch of functional components beneath that. There are exceptions to this, but in general that's how we're building Micro-Frontends with Stencil.

eswat2 commented 2 years ago

@Poimen - i was finally able to get both a testbed and my autos app to work with the next plugin (v1).

The tailwind config might have been part of my problem. I had to keep some of the older style config settings in order to get things working with the plugin. Does that make sense ??

eswat2 commented 2 years ago

in the course of doing all this, i realized that i didn't need the complexity of having 2 Components in my Sudoku app, so it's now just a single top-level Component built from a set of nested functional components. This makes it so i only need one Tailwind CLI pipeline, just like i had for my Autos app.

eswat2 commented 2 years ago

in this new configuration, i only need a single .generate script at the top-level:

#!/bin/bash
COMPONENT=proto-sudoku
DIR=./src/components/$COMPONENT
INPUT=./src/styles/app.pcss
OUTPUT=$DIR/$COMPONENT.css

if [ -f $INPUT ]
then
  if [ -d $DIR ]
  then
    echo '--' $COMPONENT
    npx tailwindcss -i $INPUT -o $OUTPUT $1
  fi
fi

That just makes it easier to call this from the package.json...

Poimen commented 2 years ago

The tailwind config might have been part of my problem. I had to keep some of the older style config settings in order to get things working with the plugin. Does that make sense ??

The older config should be fine to use, just the purge to content setting should be important.

Thanks for trying out the branch 😃

I have a feeling this would only work in a situation where you didn't use a style sheet already for the component - for instance some of our components use the :host selector to apply spacing and block vs inline-flex, as well as a grid that uses css selectors on props to generate grid layout. This would override that with the output and would not be simple to convert to tailwind syntax. I do like the arbitrary css feature in v3 but will take time to convert, and not something you want to enforce.

eswat2 commented 2 years ago

so, the way i handled existing styles was to move those into the INPUT file -- src/styles/app.pcss

again, in the simple case of only having on component it's not a big deal, but it would get complicated trying to do this for multiple components, that's where the plugin approach makes more sense

Poimen commented 2 years ago

Yup, that makes sense.

There have been a couple of others that have tested out the v1 branch with good results. I'll move that to a main release probably next week.

eswat2 commented 2 years ago

just for closure, here's a sample repo using the Tailwind CLI approach:

https://github.com/eswat2/proto-tinker-wc

it's a single top-level Component built from nested functional components...

Poimen commented 2 years ago

@eswat2 thanks for the repo 👍

Poimen commented 2 years ago

v1.1.0 has been released.

I'm closing this issue for now as general Tailwind v3 is supported.

I have re-worked a number of configuration options and postcss plugins should now be more supported without having to roll them into this. I have removed the purge and at-import plugins so you'll need to add those if you needed them. They where causing issues so pull them in if you need them.

I think the configuration of postcss separately is a bit of a better situation than baking things in.

I still need to roll this into my DS, but my example app seems to be fine in local testing. I'll do more testing tomorrow.