Rewrite esbuild postcss plugin

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-02 10:48:30 +01:00
parent 69d947b6ab
commit eef87f3907
8 changed files with 163 additions and 117 deletions

View File

@@ -42,7 +42,7 @@
"@babel/core": "^7.26.7",
"@babel/preset-env": "^7.26.7",
"@babel/preset-typescript": "^7.26.0",
"@deanc/esbuild-plugin-postcss": "^1.0.2",
"@probo/esbuild-plugin-postcss": "^0.0.1",
"@eslint/js": "^9.21.0",
"@probo/tsconfig": "^0.0.1",
"@tailwindcss/postcss": "^4.0.9",

View File

@@ -1,5 +1,5 @@
import babel from "@babel/core";
import postCssPlugin from "@deanc/esbuild-plugin-postcss";
import postCssPlugin from "@probo/esbuild-plugin-postcss";
import autoprefixer from "autoprefixer";
import { execSync, spawn } from "child_process";
import * as esbuild from "esbuild";
@@ -9,7 +9,6 @@ import path from "node:path";
import process from "node:process";
import tailwindcssPlugin from "@tailwindcss/postcss";
async function copyRecursive(src, dest) {
await fs.mkdir(dest, { recursive: true });
const files = await fs.readdir(src);

View File

@@ -1,4 +1,4 @@
@import 'tailwindcss';
@import "tailwindcss";
@plugin 'tailwindcss-animate';

View File

@@ -5,7 +5,7 @@ import { createRoot } from "react-dom/client";
import { HelmetProvider } from "react-helmet-async";
import { RelayEnvironmentProvider } from "react-relay";
import { BrowserRouter, Route, Routes, useLocation } from "react-router";
import "App.css";
import "./App.css";
import ErrorBoundary from "./components/ErrorBoundary";
import ConsoleLayout from "./layouts/ConsoleLayout";
import AuthLayout from "./layouts/AuthLayout";

131
package-lock.json generated
View File

@@ -49,8 +49,8 @@
"@babel/core": "^7.26.7",
"@babel/preset-env": "^7.26.7",
"@babel/preset-typescript": "^7.26.0",
"@deanc/esbuild-plugin-postcss": "^1.0.2",
"@eslint/js": "^9.21.0",
"@probo/esbuild-plugin-postcss": "^0.0.1",
"@probo/tsconfig": "^0.0.1",
"@tailwindcss/postcss": "^4.0.9",
"@types/babel-core": "^6.25.10",
@@ -1679,23 +1679,6 @@
"node": ">=6.9.0"
}
},
"node_modules/@deanc/esbuild-plugin-postcss": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@deanc/esbuild-plugin-postcss/-/esbuild-plugin-postcss-1.0.2.tgz",
"integrity": "sha512-+WAlrGxipNmcnr9lWlrmzC0mevQ7QqL31bMJu38AyOV44APSoqtzXh103sAkbolKxMcVhuw78m4xjdTKNjvpYA==",
"dev": true,
"license": "ISC",
"dependencies": {
"autoprefixer": "^10.2.4",
"css-tree": "^1.1.2",
"fs-extra": "^9.0.1",
"postcss": "^8.2.4",
"tmp": "^0.2.1"
},
"peerDependencies": {
"esbuild": "^0.8.32"
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
@@ -2556,6 +2539,10 @@
"resolved": "apps/console",
"link": true
},
"node_modules/@probo/esbuild-plugin-postcss": {
"resolved": "packages/esbuild-plugin-postcss",
"link": true
},
"node_modules/@probo/tsconfig": {
"resolved": "packages/tsconfig",
"link": true
@@ -4242,16 +4229,6 @@
"node": ">= 0.4"
}
},
"node_modules/at-least-node": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">= 4.0.0"
}
},
"node_modules/autoprefixer": {
"version": "10.4.20",
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
@@ -4767,20 +4744,6 @@
"node": ">= 8"
}
},
"node_modules/css-tree": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
@@ -5668,22 +5631,6 @@
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/fs-extra": {
"version": "9.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz",
"integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"at-least-node": "^1.0.0",
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@@ -6557,19 +6504,6 @@
"node": ">=6"
}
},
"node_modules/jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"universalify": "^2.0.0"
},
"optionalDependencies": {
"graceful-fs": "^4.1.6"
}
},
"node_modules/jsx-ast-utils": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
@@ -6927,13 +6861,6 @@
"node": ">= 0.4"
}
},
"node_modules/mdn-data": {
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"dev": true,
"license": "CC0-1.0"
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -6985,7 +6912,6 @@
"version": "3.3.8",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz",
"integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==",
"dev": true,
"funding": [
{
"type": "github",
@@ -7302,7 +7228,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
"dev": true,
"license": "ISC"
},
"node_modules/picomatch": {
@@ -7332,7 +7257,6 @@
"version": "8.5.1",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.1.tgz",
"integrity": "sha512-6oz2beyjc5VMn/KV1pPw8fliQkhBXrVn1Z3TVyqZxU8kZpzEKhBdmCFqI6ZbmGtamQvQGuU1sgPTk8ZrXDD7jQ==",
"dev": true,
"funding": [
{
"type": "opencollective",
@@ -8067,21 +7991,10 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
@@ -8266,16 +8179,6 @@
"node": ">=6"
}
},
"node_modules/tmp": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
"integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=14.14"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -8544,16 +8447,6 @@
"node": ">=4"
}
},
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/update-browserslist-db": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.2.tgz",
@@ -8804,6 +8697,20 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"packages/esbuild-plugin-postcss": {
"name": "@probo/esbuild-plugin-postcss",
"version": "0.0.1",
"dependencies": {
"postcss": "^8.5"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"esbuild": "^0.25.0"
},
"peerDependencies": {
"esbuild": "^0.25.0"
}
},
"packages/tsconfig": {
"name": "@probo/tsconfig",
"version": "0.0.1",

View File

@@ -0,0 +1,21 @@
{
"name": "@probo/esbuild-plugin-postcss",
"version": "0.0.1",
"exports": {
".": "./src/index.mjs"
},
"scripts": {
"test": "node tests/esbuild.test.mjs"
},
"type": "module",
"dependencies": {
"postcss": "^8.5"
},
"peerDependencies": {
"esbuild": "^0.25.0"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"esbuild": "^0.25.0"
}
}

View File

@@ -0,0 +1,52 @@
import postcss from "postcss";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
import process from "node:process";
export default (options = { plugins: [] }) => ({
name: "postcss",
setup: async function (build) {
const { rootDir = options.rootDir || process.cwd() } = options;
const tmpDirPath = await fs.mkdtemp(
path.join(os.tmpdir(), "esbuild-plugin-postcss-"),
);
build.onResolve(
{ filter: /.\.(css)$/, namespace: "file" },
async (args) => {
const resolution = await build.resolve(args.path, {
resolveDir: args.resolveDir,
kind: args.kind,
});
if (resolution.errors.length > 0) {
return { errors: resolution.errors };
}
const sourceFullPath = resolution.path;
const sourceExt = path.extname(sourceFullPath);
const sourceBaseName = path.basename(sourceFullPath, sourceExt);
const sourceDir = path.dirname(sourceFullPath);
const sourceRelDir = path.relative(path.dirname(rootDir), sourceDir);
const tmpDir = path.resolve(tmpDirPath, sourceRelDir);
const tmpFilePath = path.resolve(tmpDir, `${sourceBaseName}.css`);
await fs.mkdir(tmpDir, { recursive: true });
const css = await fs.readFile(sourceFullPath);
const result = await postcss(options.plugins).process(css, {
from: sourceFullPath,
to: tmpFilePath,
});
await fs.writeFile(tmpFilePath, result.css);
return {
path: tmpFilePath,
watchFiles: [sourceFullPath],
};
},
);
},
});

View File

@@ -0,0 +1,67 @@
import { strict as assert } from "node:assert";
import path from "node:path";
import fs from "node:fs/promises";
import os from "node:os";
import * as esbuild from "esbuild";
import postcssPlugin from "../src/index.mjs";
import postcss from "postcss";
import autoprefixer from "autoprefixer";
// Create a temporary directory for our test
const tmpDir = await fs.mkdtemp(
path.join(os.tmpdir(), "esbuild-postcss-test-"),
);
const inputFile = path.join(tmpDir, "input.css");
const outputFile = path.join(tmpDir, "output.js");
// Create a simple CSS file for testing
const cssContent = `
.example {
display: flex;
user-select: none;
}
`;
// Write the test CSS file
await fs.writeFile(inputFile, cssContent);
// Test the plugin with autoprefixer
try {
console.log("Testing PostCSS plugin with autoprefixer...");
const result = await esbuild.build({
entryPoints: [inputFile],
bundle: true,
outfile: outputFile,
plugins: [
postcssPlugin({
plugins: [autoprefixer],
}),
],
});
console.log("Build completed successfully");
const outputContent = await fs.readFile(outputFile, "utf8");
assert(
outputContent.includes("-webkit-user-select"),
"Expected -webkit-user-select to be added by autoprefixer",
);
assert(
outputContent.includes("-moz-user-select"),
"Expected -moz-user-select to be added by autoprefixer",
);
console.log("Test passed: Autoprefixer correctly processed CSS");
} catch (error) {
console.error("Test failed:", error);
process.exit(1);
} finally {
try {
await fs.rm(tmpDir, { recursive: true, force: true });
console.log("Cleaned up temporary test files");
} catch (cleanupError) {
console.warn("Warning: Failed to clean up temporary files:", cleanupError);
}
}