Update
This commit is contained in:
@ -1,7 +1,8 @@
|
||||
/* eslint-disable unicorn/string-content */
|
||||
import { promises as fs } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { type BuildOptions, type OutputFile, build, transformSync } from "esbuild";
|
||||
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
||||
import * as esbuild from "esbuild";
|
||||
import dedent from "dedent";
|
||||
import { name } from "../package.json" with { type: "json" };
|
||||
import {
|
||||
@ -24,8 +25,9 @@ describe("babel-tailwind", () => {
|
||||
});
|
||||
|
||||
it("supports ESBuild", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -36,20 +38,17 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(js.text).toContain(`className: "${clsName}"`);
|
||||
expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
expect(files.js.text).toContain(`className: "${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("does not remove the attribute if `preserveAttribute` is true", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
jsxAttributeAction: "preserve",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -60,10 +59,52 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
expect(js.text).toContain(`css: "text-center"`);
|
||||
expect(files.js.text).toContain(`css: "text-center"`);
|
||||
});
|
||||
|
||||
describe('merges with existing "className" attribute', () => {
|
||||
it("string literal", async () => {
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
<div className="text-center" css="text-center">
|
||||
Hello, world!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(files.js.text).toContain(`className: "text-center ${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("existing function", async () => {
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
<div className={({ isEntering }) => isEntering ? "enter" : "exit"} css="text-center">
|
||||
Hello, world!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(files.js.text).toContain(
|
||||
`className: ({\n isEntering\n }) => _cx(isEntering ? "enter" : "exit", "${clsName}")`
|
||||
);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
});
|
||||
|
||||
it("reports errors with correct position", async () => {
|
||||
@ -98,9 +139,10 @@ describe("babel-tailwind", () => {
|
||||
});
|
||||
|
||||
it("supports custom jsxAttributeName", async () => {
|
||||
const outputFiles = await compileESBuild({
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
jsxAttributeName: "tw",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
export function Hello() {
|
||||
return (
|
||||
@ -111,34 +153,29 @@ describe("babel-tailwind", () => {
|
||||
}
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
const clsName = getClassName("text-center");
|
||||
expect(js.text).toContain(`className: "${clsName}"`);
|
||||
expect(css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
expect(files.js.text).toContain(`className: "${clsName}"`);
|
||||
expect(files.css.text).toMatch(`.${clsName} {\n text-align: center;\n}`);
|
||||
});
|
||||
|
||||
it("supports importing tailwind/base", async () => {
|
||||
const postcss = createPostCSS({ tailwindConfig: {} });
|
||||
const base = (await postcss("@tailwind base;")).css;
|
||||
const outputFiles = await compileESBuild({
|
||||
const postcss = createPostCSS({
|
||||
tailwindConfig: {},
|
||||
postCSSPlugins: [],
|
||||
directives: [],
|
||||
});
|
||||
const base = await postcss("@tailwind base;");
|
||||
const { files } = await compileESBuild({
|
||||
clsx: "emotion",
|
||||
expectFiles: 2,
|
||||
javascript: /* tsx */ `
|
||||
import "${name}/base";
|
||||
`,
|
||||
});
|
||||
expect(outputFiles).toHaveLength(2);
|
||||
|
||||
const js = findByExt(outputFiles, ".js");
|
||||
const css = findByExt(outputFiles, ".css");
|
||||
|
||||
// expect(js.text).toContain(`import "./base.css";`);
|
||||
expect(js.text).toBe("");
|
||||
|
||||
expect(minCSS(css.text)).toContain(minCSS(base));
|
||||
expect(files.js.text).toBe("");
|
||||
expect(minCSS(files.css.text)).toContain(minCSS(base));
|
||||
});
|
||||
});
|
||||
|
||||
@ -149,37 +186,48 @@ async function write(path: string, content: string) {
|
||||
}
|
||||
|
||||
const minCSS = (text: string) =>
|
||||
transformSync(text, { minify: true, loader: "css" }).code;
|
||||
esbuild.transformSync(text, { minify: true, loader: "css" }).code;
|
||||
|
||||
const findByExt = (outputFiles: OutputFile[], ext: string) =>
|
||||
const findByExt = (outputFiles: esbuild.OutputFile[], ext: string) =>
|
||||
outputFiles.find(file => file.path.endsWith(ext))!;
|
||||
|
||||
async function compileESBuild({
|
||||
javascript,
|
||||
esbuild,
|
||||
esbuild: esbuildOptions,
|
||||
expectFiles,
|
||||
...options
|
||||
}: TailwindPluginOptions & {
|
||||
esbuild?: BuildOptions;
|
||||
esbuild?: esbuild.BuildOptions;
|
||||
javascript: string;
|
||||
expectFiles?: number;
|
||||
}) {
|
||||
const tailwind = getTailwindPlugins({
|
||||
tailwindConfig: {},
|
||||
...options,
|
||||
});
|
||||
const result = await build({
|
||||
const result = await esbuild.build({
|
||||
bundle: true,
|
||||
write: false,
|
||||
external: ["react/jsx-runtime"],
|
||||
external: ["react/jsx-runtime", "@emotion/css", "clsx"],
|
||||
outdir: "dist",
|
||||
format: "esm",
|
||||
entryPoints: [await write("index.tsx", dedent(javascript))],
|
||||
plugins: [babelPlugin({ plugins: [tailwind.babel] }), tailwind.esbuild],
|
||||
...esbuild,
|
||||
plugins: [babelPlugin({ plugins: [tailwind.babel()] }), tailwind.esbuild()],
|
||||
...esbuildOptions,
|
||||
});
|
||||
|
||||
const { errors, warnings, outputFiles } = result;
|
||||
expect(errors).toHaveLength(0);
|
||||
expect(warnings).toHaveLength(0);
|
||||
|
||||
return outputFiles!;
|
||||
if (expectFiles != null) {
|
||||
expect(outputFiles).toHaveLength(expectFiles);
|
||||
}
|
||||
|
||||
return {
|
||||
outputFiles: outputFiles!,
|
||||
files: new Proxy({} as Record<string, esbuild.OutputFile>, {
|
||||
get: (_, ext: string) => findByExt(outputFiles!, ext),
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
Reference in New Issue
Block a user