Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Tailwind to extract actual CSS rules (instead of interpreting TW classes with a cheatsheet) #47

Open
ADTC opened this issue Nov 1, 2024 · 3 comments · May be fixed by #48
Open

Comments

@ADTC
Copy link

ADTC commented Nov 1, 2024

Update: Happy to announce we have a fully working Tailwind-to-CSS converter that's server-based and doesn't depend on cheatsheets here: https://tailwind-to-css-three.vercel.app/

Source code is here: https://github.com/ADTC/tailwind_to_css


Previous Update: I made a version that does this: https://tailwind-to-css-three.vercel.app/


I think the best way to get the CSS would be to actually apply the Tailwind classes to a <div> element, and then extract the rules like this:

// Function to get applied CSS rules
function getAppliedCSSRules(element) {
  const stylesheets = Array.from(document.styleSheets);
  const appliedRules = [];

  stylesheets.forEach(sheet => {
    try {
      const rules = Array.from(sheet.cssRules);

      rules.forEach(rule => {
        if (rule.type === CSSRule.STYLE_RULE && element.matches(rule.selectorText)) {
          let css = rule.cssText;
          if (!css.startsWith('.')) return;
          css = css.substring(css.indexOf('{') + 1, css.lastIndexOf('}')).trim();
          css = css.replace(/; /g, ';\n');
          appliedRules.push(css);
        }
      });
    } catch (e) {
      console.warn('Access to stylesheet is restricted:', sheet.href);
    }
  });

  return appliedRules;
}

// Create the element
const element = document.createElement('DIV');
document.body.appendChild(element);

// Apply the Tailwind classes
element.className = input;

// Get applied CSS rules
const appliedRules = getAppliedCSSRules(element);
const concatenatedRules = appliedRules.join('\n');

// Remove the element
element.remove();
console.log(concatenatedRules); // or return the string

It will be far superior because you no longer need to have an up-to-date cheat sheet, and it will work with crazy TW classes like the ones in #45.

ADTC added a commit to ADTC/tailwind_to_css that referenced this issue Nov 1, 2024
Based on the code in Devzstudio#47

Caveat: By configuring a maximally broad safeList, all CSS classes from Tailwind will be included. This can make compilation and deployment slow, and there will be a large CSS file to download when loading the website. This is unavoidable for this new technique to work.

Also:
- Make the JSON output pretty.
- Delay processing by 1 second when typing the input, otherwise the text box is slow to show what you're typing.
@ADTC
Copy link
Author

ADTC commented Nov 1, 2024

I made a version that does this: https://tailwind-to-css-three.vercel.app/

It has completely eliminated the need for the cheatsheet by simply using Tailwind itself to generate the CSS. It seems to work well so far, but may need further testing.

Source code: https://github.com/ADTC/tailwind_to_css (Willing to open PR if this repo's owner is interested.)

@ADTC
Copy link
Author

ADTC commented Nov 1, 2024

TODO: Switch to server-side processing, which will help cover more situations like dynamic classes described in #45 which is currently still not possible.

Revert changes to tailwind config, and do this:

// pages/api/generate-css.js
import postcss from 'postcss';
import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';

export default async function handler(req, res) {
  const { classes } = req.body;

  const css = `
    @tailwind base;
    @tailwind components;
    @tailwind utilities;
    .generated {
      @apply ${classes};
    }
  `;

  try {
    const result = await postcss([tailwindcss, autoprefixer])
      .process(css, { from: undefined })
      .then(result => result.css);
    
    res.status(200).send(result);
  } catch (error) {
    res.status(500).send(error.toString());
  }
}

Inject the CSS from the API into document before generating class list. (Or somehow optimize the process to directly use the CSS from the API.)

Example code:

import { useState } from 'react';

export default function Home() {
  const [classes, setClasses] = useState('');
  const [error, setError] = useState(null);

  const handleGenerateCSS = async () => {
    try {
      const response = await fetch('/api/generate-css', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({ classes }),
      });

      if (!response.ok) throw new Error('Failed to generate CSS');

      const css = await response.text();
      const style = document.createElement('style');
      style.textContent = css;
      document.head.appendChild(style);
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <div className="container">
      <h1>Dynamic Tailwind CSS Generator</h1>
      <input
        type="text"
        value={classes}
        onChange={e => setClasses(e.target.value)}
        placeholder="Enter Tailwind CSS classes"
      />
      <button onClick={handleGenerateCSS}>Generate CSS</button>
      {error && <p style={{ color: 'red' }}>{error}</p>}
      <div className={`generated ${classes}`}>
        This is a preview with dynamic Tailwind CSS classes.
      </div>
    </div>
  );
}

ADTC added a commit to ADTC/tailwind_to_css that referenced this issue Nov 1, 2024
This will dynamically generate the Tailwind result CSS, ensuring the class to CSS rule conversion is complete, including arbitrary values in square brackets.

This also reverts the safeList changes. We will no longer need to spend a lot of time deploying, or downloading a giant list of classes. Yay, Performance Restored!!!

This is based on the new code in Devzstudio#47.

Also: Trim the CSS result when copying.
@ADTC
Copy link
Author

ADTC commented Nov 1, 2024

Update: Happy to announce we have a fully working Tailwind-to-CSS converter that's server-based and doesn't depend on cheatsheets here: https://tailwind-to-css-three.vercel.app/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant