JohnBra / vite-web-extension

Vite web extension template. Setup with React, Typescript and TailwindCSS
MIT License
504 stars 79 forks source link

Using Tailwind in content script #11

Closed TmLev closed 1 year ago

TmLev commented 1 year ago

Is there a way to use Tailwind in content scripts? Right now it doesn't seem possible to me.

I'm using style={{ ... }} as an alternative, but the experience is meh compared to Tailwind.

TmLev commented 1 year ago

Hm, seems like I can modify dist/manifest.json so that it includes Tailwind's built CSS:

  "content_scripts": [
    {
      "matches": [ ... ],
      "js": [
        "src/pages/content/index.js"
      ],
      "css": [
        "contentStyle.css",
        "assets/index-c22ca649.css" // <- This path.
      ]
    }
  ],

And with that the content script is styled with Tailwind also.

JohnBra commented 1 year ago

Hi @TmLev,

Tailwind currently can't be used in the content script. The import you added to the manifest is a dynamically generated one, so it's likely to change for future prod builds. Also, as far as I'm aware,Tailwind has an optimization step for production builds purging unused classes. I'm not sure if simply adding the tailwind build file would work in a prod build.

TmLev commented 1 year ago

So I've actually managed to make it work (only tested in Chrome's dev mode).

Here's modified make-manifest.ts which injects compiled Tailwind CSS into manifest for content script:

import * as fs from "fs";
import * as path from "path";
import colorLog from "../log";
import manifest from "../../src/manifest";
import type { PluginOption } from "vite";
import type { OutputBundle } from "rollup";

const { resolve } = path;

const outDir = resolve(__dirname, "..", "..", "public");
const outputDir = resolve(__dirname, "..", "..", "dist");

export default function makeManifest(): PluginOption {
  return {
    name: "make-manifest",
    buildEnd() {
      if (!fs.existsSync(outDir)) {
        fs.mkdirSync(outDir);
      }

      const manifestPath = resolve(outDir, "manifest.json");
      fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));

      colorLog(`Manifest file copy complete: ${manifestPath}`, "success");
    },

    generateBundle(options, bundle, isWrite: boolean): void {
      const tailwindCssAssetFileName = findCssAssetWithTailwind(
        bundle as OutputBundle
      );
      if (!tailwindCssAssetFileName) {
        throw new Error("tailwindCssAssetFileName not found");
      }

      const manifestPathInOutputDir = path.join(outputDir, "manifest.json");
      const m = JSON.parse(
        fs.readFileSync(manifestPathInOutputDir, {
          encoding: "utf-8",
        })
      ) as typeof manifest;

      const manifestWithTailwindForContentScript = {
        ...manifest,
        content_scripts: manifest.content_scripts?.map((contentScript) => ({
          ...contentScript,
          css: contentScript.css && [
            ...contentScript.css,
            tailwindCssAssetFileName,
          ],
        })),
      };
      fs.writeFileSync(
        manifestPathInOutputDir,
        JSON.stringify(manifestWithTailwindForContentScript, null, 2)
      );
    },
  };
}

const findCssAssetWithTailwind = (bundle: OutputBundle) => {
  for (const [fileName, chunkOrAsset] of Object.entries(bundle)) {
    if (chunkOrAsset.type !== "asset") {
      continue;
    }
    if (typeof chunkOrAsset.source !== "string") {
      continue;
    }
    if (!chunkOrAsset.source.includes("--tw-")) {
      continue;
    }

    return fileName;
  }

  return undefined;
};
TmLev commented 1 year ago

The only downside to this approach is that if you're trying to build content script only, then you have to also have popup (or maybe another page) with any non-empty CSS file. Otherwise, no Tailwind would be compiled and bundled to dist/assets directory.

mehimanshupatil commented 1 year ago

currently you can bundle tailwind/custom css in content script js by importing it in /src/pages/content/style.css which also purge css added in this commit https://github.com/JohnBra/vite-web-extension/pull/10/commits/2a6241ee879bd87a1fc4ac3b85f165f771c6082b

JohnBra commented 1 year ago

@mehimanshupatil Thanks for creating another PR, I highly appreciate it!

I left a comment in the PR regarding SASS.

mehimanshupatil commented 1 year ago

@JohnBra can't see your comment in PR

JohnBra commented 1 year ago

Here is what I wrote:

@mehimanshupatil Thanks again for creating a PR! I highly appreciate it!

I don't think there is a need for sass to make the content script working with TW, right?

I'd like to keep this template as lean as possible and leave decisions like adding more libs up to the dev using the template.

JohnBra commented 1 year ago

Fixed by #13

TmLev commented 1 year ago

Thanks everyone!