Fix issue
This commit is contained in:
parent
2c4b75aa6c
commit
1f5e7fa049
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@aet/tailwind",
|
"name": "@aet/tailwind",
|
||||||
"version": "1.0.20",
|
"version": "1.0.23",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
27
src/__tests__/__snapshots__/emit.test.ts.snap
Normal file
27
src/__tests__/__snapshots__/emit.test.ts.snap
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
|
exports[`emit > supports emitting as CSS module 1`] = `
|
||||||
|
"// babel-tailwind:/Users/aet/Documents/Git/babel-tailwind/src/.temp-attr/index.module.css
|
||||||
|
var index_default = {
|
||||||
|
"tw-gqn2k6": "index_tw-gqn2k6",
|
||||||
|
"tw-1qtvvjy": "index_tw-1qtvvjy"
|
||||||
|
};
|
||||||
|
|
||||||
|
import { cx as _cx } from "@emotion/css";
|
||||||
|
import { jsx } from "react/jsx-runtime";
|
||||||
|
function Hello() {
|
||||||
|
return /* @__PURE__ */ jsx("div", { className: _cx([index_default["tw-gqn2k6"], index_default["tw-1qtvvjy"]]), children: "Hello, world!" });
|
||||||
|
}
|
||||||
|
export {
|
||||||
|
Hello
|
||||||
|
};"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`emit > supports emitting as CSS module 2`] = `
|
||||||
|
".index_tw-gqn2k6 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.index_tw-1qtvvjy:hover {
|
||||||
|
font-weight: 600;
|
||||||
|
}"
|
||||||
|
`;
|
@ -1,4 +1,5 @@
|
|||||||
import { describe, it } from "vitest";
|
import { describe, it } from "vitest";
|
||||||
|
|
||||||
import { getBuild, matchSnapshot } from "./utils";
|
import { getBuild, matchSnapshot } from "./utils";
|
||||||
|
|
||||||
describe("attr", () => {
|
describe("attr", () => {
|
||||||
@ -61,7 +62,7 @@ describe("attr", () => {
|
|||||||
matchSnapshot(files);
|
matchSnapshot(files);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only("fails", async () => {
|
it("fails", async () => {
|
||||||
const { files } = await compileESBuild({
|
const { files } = await compileESBuild({
|
||||||
clsx: "emotion",
|
clsx: "emotion",
|
||||||
expectFiles: 2,
|
expectFiles: 2,
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { createPostCSS } from "../index";
|
import { createPostCSS } from "../index";
|
||||||
|
|
||||||
import { getBuild, minCSS, name } from "./utils";
|
import { getBuild, minCSS, name } from "./utils";
|
||||||
|
|
||||||
describe("babel-tailwind", () => {
|
describe("babel-tailwind", () => {
|
||||||
|
26
src/__tests__/emit.test.ts
Normal file
26
src/__tests__/emit.test.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { describe, it } from "vitest";
|
||||||
|
|
||||||
|
import { getBuild, matchSnapshot } from "./utils";
|
||||||
|
|
||||||
|
describe("emit", () => {
|
||||||
|
const compileESBuild = getBuild("attr");
|
||||||
|
|
||||||
|
it("supports emitting as CSS module", async () => {
|
||||||
|
const { files } = await compileESBuild({
|
||||||
|
clsx: "emotion",
|
||||||
|
expectFiles: 2,
|
||||||
|
cssModules: true,
|
||||||
|
javascript: /* tsx */ `
|
||||||
|
export function Hello() {
|
||||||
|
return (
|
||||||
|
<div css={["text-center", { hover: "font-semibold" }]}>
|
||||||
|
Hello, world!
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
matchSnapshot(files);
|
||||||
|
});
|
||||||
|
});
|
@ -1,6 +1,8 @@
|
|||||||
/* eslint-disable unicorn/string-content */
|
/* eslint-disable unicorn/string-content */
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { getClassName } from "../index";
|
import { getClassName } from "../index";
|
||||||
|
|
||||||
import { getBuild } from "./utils";
|
import { getBuild } from "./utils";
|
||||||
|
|
||||||
describe("merges with existing className attribute", () => {
|
describe("merges with existing className attribute", () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { getBuild, matchSnapshot } from "./utils";
|
import { getBuild, matchSnapshot } from "./utils";
|
||||||
|
|
||||||
describe("options", () => {
|
describe("options", () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { describe, it } from "vitest";
|
import { describe, it } from "vitest";
|
||||||
|
|
||||||
import { getBuild, matchSnapshot } from "./utils";
|
import { getBuild, matchSnapshot } from "./utils";
|
||||||
|
|
||||||
describe("babel-tailwind", () => {
|
describe("babel-tailwind", () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { describe, it } from "vitest";
|
import { describe, it } from "vitest";
|
||||||
|
|
||||||
import { getBuild, matchSnapshot } from "./utils";
|
import { getBuild, matchSnapshot } from "./utils";
|
||||||
|
|
||||||
describe("babel-tailwind", () => {
|
describe("babel-tailwind", () => {
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { promises as fs } from "node:fs";
|
import { promises as fs } from "node:fs";
|
||||||
import { join, resolve } from "node:path";
|
import { join, resolve } from "node:path";
|
||||||
import { afterEach, beforeEach, expect } from "vitest";
|
|
||||||
import * as esbuild from "esbuild";
|
|
||||||
import dedent from "dedent";
|
import dedent from "dedent";
|
||||||
|
import * as esbuild from "esbuild";
|
||||||
|
import { afterEach, beforeEach, expect } from "vitest";
|
||||||
|
|
||||||
import { type TailwindPluginOptions, babelPlugin, getTailwindPlugins } from "../index";
|
import { type TailwindPluginOptions, babelPlugin, getTailwindPlugins } from "../index";
|
||||||
|
|
||||||
export { name } from "../../package.json" with { type: "json" };
|
export { name } from "../../package.json" with { type: "json" };
|
||||||
|
@ -35,12 +35,14 @@ function getUtils({
|
|||||||
clsx,
|
clsx,
|
||||||
getClassName: getClass = getClassName,
|
getClassName: getClass = getClassName,
|
||||||
vite: bustCache,
|
vite: bustCache,
|
||||||
|
cssModules,
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
let cx: t.Identifier;
|
let cx: t.Identifier;
|
||||||
let tslibImport: t.Identifier;
|
let tslibImport: t.Identifier;
|
||||||
let styleImport: t.Identifier;
|
let styleImport: t.Identifier;
|
||||||
let classedImport: t.Identifier;
|
let classedImport: t.Identifier;
|
||||||
|
let cssModuleImport: t.Identifier;
|
||||||
|
|
||||||
const cssMap = new Map<string, StyleMapEntry>();
|
const cssMap = new Map<string, StyleMapEntry>();
|
||||||
const jsMap = new Map<string, StyleMapEntry>();
|
const jsMap = new Map<string, StyleMapEntry>();
|
||||||
@ -50,6 +52,13 @@ function getUtils({
|
|||||||
return t.cloneNode(styleImport);
|
return t.cloneNode(styleImport);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getCssModuleImport = () => {
|
||||||
|
if (cssModuleImport == null) {
|
||||||
|
cssModuleImport = path.scope.generateUidIdentifier("cssModule");
|
||||||
|
}
|
||||||
|
return t.cloneNode(cssModuleImport);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getClass(type: Type, value: string) {
|
getClass(type: Type, value: string) {
|
||||||
return type === "css" ? getClass(value) : "tw_" + hash(value);
|
return type === "css" ? getClass(value) : "tw_" + hash(value);
|
||||||
@ -65,7 +74,7 @@ function getUtils({
|
|||||||
.join("\n"),
|
.join("\n"),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
recordIfAbsent(type: Type, entry: StyleMapEntry) {
|
recordIfAbsent(type: "css", entry: StyleMapEntry) {
|
||||||
const map = type === "css" ? cssMap : jsMap;
|
const map = type === "css" ? cssMap : jsMap;
|
||||||
if (!map.has(entry.key)) {
|
if (!map.has(entry.key)) {
|
||||||
map.set(entry.key, entry);
|
map.set(entry.key, entry);
|
||||||
@ -125,18 +134,44 @@ function getUtils({
|
|||||||
return t.cloneNode(classedImport);
|
return t.cloneNode(classedImport);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getCssModuleImport,
|
||||||
|
|
||||||
|
getClassNameValue: (className: string) => {
|
||||||
|
const validId = t.isValidIdentifier(className);
|
||||||
|
return cssModules
|
||||||
|
? t.memberExpression(
|
||||||
|
getCssModuleImport(),
|
||||||
|
validId ? t.identifier(className) : t.stringLiteral(className),
|
||||||
|
!validId
|
||||||
|
)
|
||||||
|
: t.stringLiteral(className);
|
||||||
|
},
|
||||||
|
|
||||||
finish(node: t.Program) {
|
finish(node: t.Program) {
|
||||||
const { filename } = state;
|
const { filename } = state;
|
||||||
if (!cssMap.size && !jsMap.size) return;
|
if (!cssMap.size && !jsMap.size) return;
|
||||||
invariant(filename, "babel: missing state.filename");
|
invariant(filename, "babel: missing state.filename");
|
||||||
|
|
||||||
if (cssMap.size) {
|
if (cssMap.size) {
|
||||||
const cssName = basename(filename, extname(filename)) + ".css";
|
const cssName =
|
||||||
|
basename(filename, extname(filename)) +
|
||||||
|
(cssModuleImport ? ".module" : "") +
|
||||||
|
".css";
|
||||||
const path = join(dirname(filename), cssName);
|
const path = join(dirname(filename), cssName);
|
||||||
const value = Array.from(cssMap.values());
|
const value = Array.from(cssMap.values());
|
||||||
const importee = `tailwind:./${cssName}` + getSuffix(bustCache, value);
|
|
||||||
|
|
||||||
|
if (cssModuleImport) {
|
||||||
|
const importee = `tailwind:./${cssName}` + getSuffix(bustCache, value);
|
||||||
|
node.body.unshift(
|
||||||
|
t.importDeclaration(
|
||||||
|
[t.importDefaultSpecifier(cssModuleImport)],
|
||||||
|
t.stringLiteral(importee)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const importee = `tailwind:./${cssName}` + getSuffix(bustCache, value);
|
||||||
node.body.unshift(t.importDeclaration([], t.stringLiteral(importee)));
|
node.body.unshift(t.importDeclaration([], t.stringLiteral(importee)));
|
||||||
|
}
|
||||||
|
|
||||||
styleMap.set(path, value);
|
styleMap.set(path, value);
|
||||||
onCollect?.(path, value);
|
onCollect?.(path, value);
|
||||||
@ -212,7 +247,7 @@ export function babelTailwind(
|
|||||||
classNames: trimmed,
|
classNames: trimmed,
|
||||||
location: _.sliceText(node),
|
location: _.sliceText(node),
|
||||||
});
|
});
|
||||||
path.replaceWith(t.stringLiteral(className));
|
path.replaceWith(_.getClassNameValue(className));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ArrayExpression(path) {
|
ArrayExpression(path) {
|
||||||
@ -228,7 +263,7 @@ export function babelTailwind(
|
|||||||
classNames: trimmed,
|
classNames: trimmed,
|
||||||
location: _.sliceText(path.node),
|
location: _.sliceText(path.node),
|
||||||
});
|
});
|
||||||
path.replaceWith(t.stringLiteral(className));
|
path.replaceWith(_.getClassNameValue(className));
|
||||||
},
|
},
|
||||||
JSXExpressionContainer(path) {
|
JSXExpressionContainer(path) {
|
||||||
go(path.get("expression"));
|
go(path.get("expression"));
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { readFileSync } from "node:fs";
|
import { readFileSync } from "node:fs";
|
||||||
import { extname } from "node:path";
|
import { extname } from "node:path";
|
||||||
import { once } from "lodash-es";
|
|
||||||
import type babel from "@babel/core";
|
import type babel from "@babel/core";
|
||||||
import type * as esbuild from "esbuild";
|
|
||||||
import { transformSync } from "@babel/core";
|
import { transformSync } from "@babel/core";
|
||||||
|
import type * as esbuild from "esbuild";
|
||||||
|
import { once } from "lodash-es";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An esbuild plugin that processes files with Babel if `plugins` is not empty.
|
* An esbuild plugin that processes files with Babel if `plugins` is not empty.
|
||||||
|
21
src/index.ts
21
src/index.ts
@ -19,7 +19,7 @@ export { createPostCSS } from "./shared";
|
|||||||
type GetClassName = (className: string) => string;
|
type GetClassName = (className: string) => string;
|
||||||
export type BuildStyleFile = (
|
export type BuildStyleFile = (
|
||||||
path: string
|
path: string
|
||||||
) => Promise<readonly ["css", string] | readonly ["js", string]>;
|
) => Promise<readonly ["css" | "local-css", string] | readonly ["js", string]>;
|
||||||
|
|
||||||
export interface TailwindPluginOptions {
|
export interface TailwindPluginOptions {
|
||||||
/**
|
/**
|
||||||
@ -86,6 +86,17 @@ export interface TailwindPluginOptions {
|
|||||||
* Keep the original classnames in the CSS output
|
* Keep the original classnames in the CSS output
|
||||||
*/
|
*/
|
||||||
addSourceAsComment?: boolean;
|
addSourceAsComment?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit as CSS modules
|
||||||
|
*/
|
||||||
|
cssModules?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emit type. `css-import` for plain CSS import,
|
||||||
|
* `css-module` for CSS modules, `css-in-js` for JS.
|
||||||
|
*/
|
||||||
|
// emitType: "css-import" | "css-module" | "css-in-js";
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ResolveTailwindOptions = SetRequired<
|
export type ResolveTailwindOptions = SetRequired<
|
||||||
@ -121,7 +132,7 @@ export const getClassName: GetClassName = cls => "tw-" + hash(cls);
|
|||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export function getTailwindPlugins(options: TailwindPluginOptions) {
|
export function getTailwindPlugins(options: TailwindPluginOptions) {
|
||||||
const { addSourceAsComment, compile: _compile } = options;
|
const { addSourceAsComment, compile: _compile, cssModules } = options;
|
||||||
const resolvedOptions: ResolveTailwindOptions = {
|
const resolvedOptions: ResolveTailwindOptions = {
|
||||||
getClassName,
|
getClassName,
|
||||||
jsxAttributeAction: "delete",
|
jsxAttributeAction: "delete",
|
||||||
@ -155,7 +166,10 @@ export function getTailwindPlugins(options: TailwindPluginOptions) {
|
|||||||
.join("\n")
|
.join("\n")
|
||||||
);
|
);
|
||||||
if (path.endsWith(".css")) {
|
if (path.endsWith(".css")) {
|
||||||
return ["css", transformSync(compiled, { loader: "css" }).code] as const;
|
return [
|
||||||
|
cssModules ? "local-css" : "css",
|
||||||
|
transformSync(compiled, { loader: "css" }).code,
|
||||||
|
] as const;
|
||||||
} else if (path.endsWith(".js")) {
|
} else if (path.endsWith(".js")) {
|
||||||
const js = toJSCode(compiled, x => x.slice(1));
|
const js = toJSCode(compiled, x => x.slice(1));
|
||||||
return ["js", js] as const;
|
return ["js", js] as const;
|
||||||
@ -176,6 +190,7 @@ export function getTailwindPlugins(options: TailwindPluginOptions) {
|
|||||||
styleMap,
|
styleMap,
|
||||||
options,
|
options,
|
||||||
getCompiler,
|
getCompiler,
|
||||||
|
buildStyleFile,
|
||||||
[Symbol.dispose]() {
|
[Symbol.dispose]() {
|
||||||
styleMap.clear();
|
styleMap.clear();
|
||||||
},
|
},
|
||||||
|
13
src/vendor/animate.ts
vendored
13
src/vendor/animate.ts
vendored
@ -1,4 +1,5 @@
|
|||||||
// https://github.com/jamiebuilds/tailwindcss-animate/commit/ac0dd3a3c81681b78f1d8ea5e7478044213995e1
|
// https://github.com/jamiebuilds/tailwindcss-animate/commit/ac0dd3a3c81681b78f1d8ea5e7478044213995e1
|
||||||
|
// https://github.com/tailwindlabs/tailwindcss/discussions/11164#discussioncomment-5819097
|
||||||
import plugin from "tailwindcss/plugin.js";
|
import plugin from "tailwindcss/plugin.js";
|
||||||
import type { PluginAPI } from "tailwindcss/types/config";
|
import type { PluginAPI } from "tailwindcss/types/config";
|
||||||
|
|
||||||
@ -11,11 +12,7 @@ function filterDefault<T extends object>(values: T) {
|
|||||||
export default plugin(
|
export default plugin(
|
||||||
({ addUtilities, matchUtilities, theme }) => {
|
({ addUtilities, matchUtilities, theme }) => {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
"@keyframes enter": theme("keyframes.enter"),
|
|
||||||
"@keyframes exit": theme("keyframes.exit"),
|
|
||||||
".animate-in": {
|
".animate-in": {
|
||||||
animationName: "enter",
|
|
||||||
animationDuration: theme("animationDuration.DEFAULT"),
|
|
||||||
"--tw-enter-opacity": "initial",
|
"--tw-enter-opacity": "initial",
|
||||||
"--tw-enter-scale": "initial",
|
"--tw-enter-scale": "initial",
|
||||||
"--tw-enter-rotate": "initial",
|
"--tw-enter-rotate": "initial",
|
||||||
@ -23,8 +20,6 @@ export default plugin(
|
|||||||
"--tw-enter-translate-y": "initial",
|
"--tw-enter-translate-y": "initial",
|
||||||
},
|
},
|
||||||
".animate-out": {
|
".animate-out": {
|
||||||
animationName: "exit",
|
|
||||||
animationDuration: theme("animationDuration.DEFAULT"),
|
|
||||||
"--tw-exit-opacity": "initial",
|
"--tw-exit-opacity": "initial",
|
||||||
"--tw-exit-scale": "initial",
|
"--tw-exit-scale": "initial",
|
||||||
"--tw-exit-rotate": "initial",
|
"--tw-exit-rotate": "initial",
|
||||||
@ -168,6 +163,10 @@ export default plugin(
|
|||||||
1: "1",
|
1: "1",
|
||||||
infinite: "infinite",
|
infinite: "infinite",
|
||||||
},
|
},
|
||||||
|
animation: ({ theme }) => ({
|
||||||
|
out: `leave ${theme("animationDuration.DEFAULT")}`,
|
||||||
|
in: `enter ${theme("animationDuration.DEFAULT")}`,
|
||||||
|
}),
|
||||||
keyframes: {
|
keyframes: {
|
||||||
enter: {
|
enter: {
|
||||||
from: {
|
from: {
|
||||||
@ -176,7 +175,7 @@ export default plugin(
|
|||||||
"translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))",
|
"translate3d(var(--tw-enter-translate-x, 0), var(--tw-enter-translate-y, 0), 0) scale3d(var(--tw-enter-scale, 1), var(--tw-enter-scale, 1), var(--tw-enter-scale, 1)) rotate(var(--tw-enter-rotate, 0))",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
exit: {
|
leave: {
|
||||||
to: {
|
to: {
|
||||||
opacity: "var(--tw-exit-opacity, 1)",
|
opacity: "var(--tw-exit-opacity, 1)",
|
||||||
transform:
|
transform:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user