This commit is contained in:
Alex 2024-04-07 21:18:45 -04:00
parent 4114914eea
commit bec8b92669
5 changed files with 31 additions and 15 deletions

View File

@ -1 +1,9 @@
# babel-tailwind # babel-tailwind
Compile-run Tailwind compiler.
```tsx
export function App() {
return <div css="flex m-0"></div>;
}
```

View File

@ -1,6 +1,6 @@
{ {
"name": "@aet/babel-tailwind", "name": "@aet/babel-tailwind",
"version": "0.0.1-beta.5", "version": "0.0.1-beta.7",
"main": "dist/index.js", "main": "dist/index.js",
"license": "MIT", "license": "MIT",
"private": true, "private": true,

View File

@ -4,12 +4,6 @@ import { type NodePath, type types as t } from "@babel/core";
import type { SourceLocation, StyleMap, StyleMapEntry } from "./shared"; import type { SourceLocation, StyleMap, StyleMapEntry } from "./shared";
import { type TailwindPluginOptions, getClassName } from "./index"; import { type TailwindPluginOptions, getClassName } from "./index";
interface BabelPluginState {
getCx: () => t.Identifier;
sliceText: (node: t.Node) => SourceLocation;
tailwindMap: Map<string, StyleMapEntry>;
}
const definePlugin = const definePlugin =
<T>(fn: (runtime: typeof babel) => babel.Visitor<babel.PluginPass & T>) => <T>(fn: (runtime: typeof babel) => babel.Visitor<babel.PluginPass & T>) =>
(runtime: typeof babel) => { (runtime: typeof babel) => {
@ -31,6 +25,13 @@ function matchPath(
fn?.(nodePath); fn?.(nodePath);
} }
interface BabelPluginState {
getCx: () => t.Identifier;
sliceText: (node: t.Node) => SourceLocation;
recordIfAbsent: (node: StyleMapEntry) => void;
tailwindMap: Map<string, StyleMapEntry>;
}
export function babelTailwind( export function babelTailwind(
styleMap: StyleMap, styleMap: StyleMap,
{ {
@ -67,7 +68,7 @@ export function babelTailwind(
Program: { Program: {
enter(path, state) { enter(path, state) {
let cx: t.Identifier; let cx: t.Identifier;
state.tailwindMap = new Map(); const map = (state.tailwindMap = new Map());
state.sliceText = node => ({ state.sliceText = node => ({
filename: state.filename!, filename: state.filename!,
start: node.loc!.start, start: node.loc!.start,
@ -77,6 +78,11 @@ export function babelTailwind(
.slice(node.loc!.start.line - 1, node.loc!.end.line) .slice(node.loc!.start.line - 1, node.loc!.end.line)
.join("\n"), .join("\n"),
}); });
state.recordIfAbsent = entry => {
if (!map.has(entry.key)) {
map.set(entry.key, entry);
}
};
state.getCx = () => { state.getCx = () => {
if (cx == null) { if (cx == null) {
cx = path.scope.generateUidIdentifier("cx"); cx = path.scope.generateUidIdentifier("cx");
@ -101,7 +107,7 @@ export function babelTailwind(
}, },
}, },
TaggedTemplateExpression(path, { tailwindMap, sliceText }) { TaggedTemplateExpression(path, { sliceText, recordIfAbsent }) {
if (taggedTemplateName == null) return; if (taggedTemplateName == null) return;
const { node } = path; const { node } = path;
@ -119,7 +125,7 @@ export function babelTailwind(
if (value) { if (value) {
const trimmed = value.replace(/\s+/g, " ").trim(); const trimmed = value.replace(/\s+/g, " ").trim();
const className = getClass(trimmed); const className = getClass(trimmed);
tailwindMap.set(className, { recordIfAbsent({
key: className, key: className,
className: trimmed, className: trimmed,
location: sliceText(node), location: sliceText(node),
@ -128,7 +134,7 @@ export function babelTailwind(
} }
}, },
JSXAttribute(path, { tailwindMap, sliceText, getCx }) { JSXAttribute(path, { sliceText, recordIfAbsent, getCx }) {
const { name } = path.node; const { name } = path.node;
if (name.name !== jsxAttributeName) return; if (name.name !== jsxAttributeName) return;
@ -152,7 +158,7 @@ export function babelTailwind(
if (value) { if (value) {
const trimmed = value.replace(/\s+/g, " ").trim(); const trimmed = value.replace(/\s+/g, " ").trim();
const className = getClass(trimmed); const className = getClass(trimmed);
tailwindMap.set(className, { recordIfAbsent({
key: className, key: className,
className: trimmed, className: trimmed,
location: sliceText(node), location: sliceText(node),

View File

@ -1,6 +1,7 @@
import hash from "@emotion/hash"; import hash from "@emotion/hash";
import type { Config } from "tailwindcss"; import type { Config } from "tailwindcss";
import type postcss from "postcss"; import type postcss from "postcss";
import { memoize } from "lodash";
import { babelTailwind } from "./babel-tailwind"; import { babelTailwind } from "./babel-tailwind";
import { esbuildPlugin } from "./esbuild-postcss"; import { esbuildPlugin } from "./esbuild-postcss";
import { vitePlugin } from "./vite-plugin"; import { vitePlugin } from "./vite-plugin";
@ -90,7 +91,7 @@ export const getClassName: GetClassName = cls => "tw-" + hash(cls);
*/ */
export function getTailwindPlugins(options: TailwindPluginOptions) { export function getTailwindPlugins(options: TailwindPluginOptions) {
const styleMap: StyleMap = new Map(); const styleMap: StyleMap = new Map();
const compile = createPostCSS(options); const compile = memoize(createPostCSS(options));
return { return {
compile, compile,

View File

@ -1,5 +1,6 @@
import { dirname, join } from "node:path"; import { dirname, join } from "node:path";
import type * as vite from "vite"; import type * as vite from "vite";
import { memoize } from "lodash";
import { type Compile, type StyleMap, pkgName, toCSSText } from "./shared"; import { type Compile, type StyleMap, pkgName, toCSSText } from "./shared";
const ROLLUP_PREFIX = "\0tailwind:"; const ROLLUP_PREFIX = "\0tailwind:";
@ -28,7 +29,7 @@ export const vitePlugin = (styleMap: StyleMap, compile: Compile): vite.Plugin =>
if (id.startsWith(ROLLUP_PREFIX)) { if (id.startsWith(ROLLUP_PREFIX)) {
const resolved = id.slice(ROLLUP_PREFIX.length); const resolved = id.slice(ROLLUP_PREFIX.length);
if (resolved === "directive:base") { if (resolved === "directive:base") {
return (await compile("@tailwind base;")).css; return (await compile("@tailwind base")).css;
} }
if (styleMap.has(resolved)) { if (styleMap.has(resolved)) {