Export more stuffs

This commit is contained in:
Alex 2024-03-30 20:35:26 -04:00
parent 7176f72cbf
commit 8f6e77f899
5 changed files with 90 additions and 43 deletions

View File

@ -11,10 +11,10 @@
"dist" "dist"
], ],
"devDependencies": { "devDependencies": {
"@aet/eslint-rules": "^0.0.18", "@aet/eslint-rules": "^0.0.19",
"@types/babel__core": "^7.20.5", "@types/babel__core": "^7.20.5",
"@types/lodash": "^4.17.0", "@types/lodash": "^4.17.0",
"@types/node": "^20.11.30", "@types/node": "^20.12.2",
"esbuild": "^0.20.2", "esbuild": "^0.20.2",
"esbuild-register": "^3.5.0", "esbuild-register": "^3.5.0",
"prettier": "^3.2.5", "prettier": "^3.2.5",

34
pnpm-lock.yaml generated
View File

@ -20,8 +20,8 @@ dependencies:
devDependencies: devDependencies:
'@aet/eslint-rules': '@aet/eslint-rules':
specifier: ^0.0.18 specifier: ^0.0.19
version: 0.0.18(eslint@8.57.0)(typescript@5.4.3) version: 0.0.19(eslint@8.57.0)(typescript@5.4.3)
'@types/babel__core': '@types/babel__core':
specifier: ^7.20.5 specifier: ^7.20.5
version: 7.20.5 version: 7.20.5
@ -29,8 +29,8 @@ devDependencies:
specifier: ^4.17.0 specifier: ^4.17.0
version: 4.17.0 version: 4.17.0
'@types/node': '@types/node':
specifier: ^20.11.30 specifier: ^20.12.2
version: 20.11.30 version: 20.12.2
esbuild: esbuild:
specifier: ^0.20.2 specifier: ^0.20.2
version: 0.20.2 version: 0.20.2
@ -51,7 +51,7 @@ devDependencies:
version: 5.4.3 version: 5.4.3
vitest: vitest:
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0(@types/node@20.11.30) version: 1.4.0(@types/node@20.12.2)
packages: packages:
@ -60,8 +60,8 @@ packages:
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
dev: true dev: true
/@aet/eslint-rules@0.0.18(eslint@8.57.0)(typescript@5.4.3): /@aet/eslint-rules@0.0.19(eslint@8.57.0)(typescript@5.4.3):
resolution: {integrity: sha512-Pq+7cF+bOZUASsTjGgcrVMzTv2rnVQvY6AWlYEIF0t+0WT7LNoTs882tBCfyi5tKFL/4uZFNaSfhVlxiV71h0A==} resolution: {integrity: sha512-RO9JBZcdY2HVvWPvqlob2yNwszXwOPUL81uXCg3IrjDi7Ka48zWsfEyMpF/w/3jNgwhYxDBLTJAhHABuJ2LtXQ==}
peerDependencies: peerDependencies:
eslint: ^8.53.0 eslint: ^8.53.0
typescript: ^5.2.2 typescript: ^5.2.2
@ -1034,8 +1034,8 @@ packages:
resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==} resolution: {integrity: sha512-t7dhREVv6dbNj0q17X12j7yDG4bD/DHYX7o5/DbDxobP0HnGPgpRz2Ej77aL7TZT3DSw13fqUTj8J4mMnqa7WA==}
dev: true dev: true
/@types/node@20.11.30: /@types/node@20.12.2:
resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==}
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
dev: true dev: true
@ -3402,7 +3402,7 @@ packages:
spdx-expression-parse: 3.0.1 spdx-expression-parse: 3.0.1
dev: true dev: true
/vite-node@1.4.0(@types/node@20.11.30): /vite-node@1.4.0(@types/node@20.12.2):
resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
@ -3411,7 +3411,7 @@ packages:
debug: 4.3.4 debug: 4.3.4
pathe: 1.1.2 pathe: 1.1.2
picocolors: 1.0.0 picocolors: 1.0.0
vite: 5.2.7(@types/node@20.11.30) vite: 5.2.7(@types/node@20.12.2)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- less - less
@ -3423,7 +3423,7 @@ packages:
- terser - terser
dev: true dev: true
/vite@5.2.7(@types/node@20.11.30): /vite@5.2.7(@types/node@20.12.2):
resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==} resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
@ -3451,7 +3451,7 @@ packages:
terser: terser:
optional: true optional: true
dependencies: dependencies:
'@types/node': 20.11.30 '@types/node': 20.12.2
esbuild: 0.20.2 esbuild: 0.20.2
postcss: 8.4.38 postcss: 8.4.38
rollup: 4.13.2 rollup: 4.13.2
@ -3459,7 +3459,7 @@ packages:
fsevents: 2.3.3 fsevents: 2.3.3
dev: true dev: true
/vitest@1.4.0(@types/node@20.11.30): /vitest@1.4.0(@types/node@20.12.2):
resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==} resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==}
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
@ -3484,7 +3484,7 @@ packages:
jsdom: jsdom:
optional: true optional: true
dependencies: dependencies:
'@types/node': 20.11.30 '@types/node': 20.12.2
'@vitest/expect': 1.4.0 '@vitest/expect': 1.4.0
'@vitest/runner': 1.4.0 '@vitest/runner': 1.4.0
'@vitest/snapshot': 1.4.0 '@vitest/snapshot': 1.4.0
@ -3502,8 +3502,8 @@ packages:
strip-literal: 2.1.0 strip-literal: 2.1.0
tinybench: 2.6.0 tinybench: 2.6.0
tinypool: 0.8.3 tinypool: 0.8.3
vite: 5.2.7(@types/node@20.11.30) vite: 5.2.7(@types/node@20.12.2)
vite-node: 1.4.0(@types/node@20.11.30) vite-node: 1.4.0(@types/node@20.12.2)
why-is-node-running: 2.2.2 why-is-node-running: 2.2.2
transitivePeerDependencies: transitivePeerDependencies:
- less - less

View File

@ -2,6 +2,9 @@ import { promises as fs } from "node:fs";
import { resolve } from "node:path"; import { resolve } from "node:path";
import { build } from "esbuild"; import { build } from "esbuild";
import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { OutputChunk, rollup } from "rollup";
import rollupBabel from "@rollup/plugin-babel";
import rollupCSS from "rollup-plugin-css-only";
import { import {
type TailwindPluginOptions, type TailwindPluginOptions,
babelPlugin, babelPlugin,
@ -26,7 +29,7 @@ describe("babel-tailwind", () => {
return resolved; return resolved;
} }
async function compile(options: TailwindPluginOptions, javascript: string) { async function compileESBuild(options: TailwindPluginOptions, javascript: string) {
const tailwind = getTailwindPlugins(options); const tailwind = getTailwindPlugins(options);
const result = await build({ const result = await build({
bundle: true, bundle: true,
@ -45,8 +48,8 @@ describe("babel-tailwind", () => {
return outputFiles; return outputFiles;
} }
it("renders", async () => { it("supports ESBuild", async () => {
const outputFiles = await compile( const outputFiles = await compileESBuild(
{ {
tailwindConfig: {}, tailwindConfig: {},
clsx: "emotion", clsx: "emotion",

View File

@ -3,11 +3,14 @@ import { basename, dirname, extname, join } from "node:path";
import { once } from "lodash"; import { once } from "lodash";
import hash from "@emotion/hash"; import hash from "@emotion/hash";
import type babel from "@babel/core"; import type babel from "@babel/core";
import { type NodePath, type types as t, transform } from "@babel/core"; import { type NodePath, type types as t, transformSync } from "@babel/core";
import { type Plugin } from "esbuild"; import type * as esbuild from "esbuild";
import tailwind, { type Config } from "tailwindcss"; import tailwind, { type Config } from "tailwindcss";
import postcss from "postcss"; import postcss from "postcss";
const PLUGIN_NAME = "tailwind";
const ESBUILD_NAMESPACE = "babel-tailwind";
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) => {
@ -29,8 +32,6 @@ function matchPath(
fn?.(nodePath); fn?.(nodePath);
} }
const ESBUILD_NAMESPACE = "babel-tailwind";
export interface TailwindPluginOptions { export interface TailwindPluginOptions {
/** /**
* Tailwind CSS configuration * Tailwind CSS configuration
@ -226,7 +227,7 @@ export const babelPlugin = ({
}: { }: {
filter?: RegExp; filter?: RegExp;
getPlugins(file: { path: string; contents: string }): babel.PluginItem[]; getPlugins(file: { path: string; contents: string }): babel.PluginItem[];
}): Plugin => ({ }): esbuild.Plugin => ({
name: "babel-plugin", name: "babel-plugin",
setup(build) { setup(build) {
build.onLoad({ filter }, ({ path }) => { build.onLoad({ filter }, ({ path }) => {
@ -242,7 +243,7 @@ export const babelPlugin = ({
return; return;
} }
const { code } = transform(load(), { const { code } = transformSync(load(), {
parserOpts: { parserOpts: {
plugins: ["jsx", "typescript"], plugins: ["jsx", "typescript"],
}, },
@ -258,21 +259,26 @@ export const babelPlugin = ({
}, },
}); });
const tailwindPlugin = ( type Compile = ReturnType<typeof createPostCSS>;
function createPostCSS({ tailwindConfig, postCSSPlugins = [] }: TailwindPluginOptions) {
const post = postcss([
tailwind({
...tailwindConfig,
content: [{ raw: "<br>", extension: "html" }],
}),
...postCSSPlugins,
]);
return (css: string) => post.process(css, { from: undefined });
}
const esbuildPlugin = (
styleMap: Map<string, string>, styleMap: Map<string, string>,
{ tailwindConfig, postCSSPlugins = [] }: TailwindPluginOptions compile: Compile
): Plugin => ({ ): esbuild.Plugin => ({
name: "tailwind", name: PLUGIN_NAME,
setup(build) { setup(build) {
const post = postcss([
tailwind({
...tailwindConfig,
content: [{ raw: "<br>", extension: "html" }],
}),
...postCSSPlugins,
]);
build.onResolve({ filter: /^tailwind:.+\.css$/ }, ({ path, importer }) => { build.onResolve({ filter: /^tailwind:.+\.css$/ }, ({ path, importer }) => {
const resolved = join(dirname(importer), path.replace(/^tailwind:/, "")); const resolved = join(dirname(importer), path.replace(/^tailwind:/, ""));
if (styleMap.has(resolved)) { if (styleMap.has(resolved)) {
@ -285,7 +291,7 @@ const tailwindPlugin = (
build.onLoad({ filter: /.*/, namespace: ESBUILD_NAMESPACE }, async ({ path }) => { build.onLoad({ filter: /.*/, namespace: ESBUILD_NAMESPACE }, async ({ path }) => {
if (!styleMap.has(path)) return; if (!styleMap.has(path)) return;
const result = await post.process(styleMap.get(path)!, { from: undefined }); const result = await compile(styleMap.get(path)!);
return { return {
contents: result.css, contents: result.css,
@ -296,7 +302,9 @@ const tailwindPlugin = (
}); });
/** /**
* Main entry. Returns the esbuild and babel plugins for tailwind. * Main entry. Returns the esbuild, babel plugins and utilities for processing
* Tailwind classNames in JS.
*
* @example * @example
* import { build } from "esbuild"; * import { build } from "esbuild";
* import getTailwindPlugins, { babelPlugin } from "babel-tailwind"; * import getTailwindPlugins, { babelPlugin } from "babel-tailwind";
@ -311,9 +319,13 @@ const tailwindPlugin = (
*/ */
export function getTailwindPlugins(options: TailwindPluginOptions) { export function getTailwindPlugins(options: TailwindPluginOptions) {
const styleMap = new Map<string, string>(); const styleMap = new Map<string, string>();
const compile = createPostCSS(options);
return { return {
compile,
babel: babelTailwind(styleMap, options), babel: babelTailwind(styleMap, options),
esbuild: tailwindPlugin(styleMap, options), esbuild: esbuildPlugin(styleMap, compile),
styleMap,
[Symbol.dispose]() { [Symbol.dispose]() {
styleMap.clear(); styleMap.clear();
}, },

32
src/modules.d.ts vendored Normal file
View File

@ -0,0 +1,32 @@
declare module "rollup-plugin-css-only" {
import { OutputBundle, Plugin } from "rollup";
namespace css {
interface Options {
/**
* All CSS files will be parsed by default, but you can also specifically include files
*/
include?: ReadonlyArray<string | RegExp> | string | RegExp | null;
/**
* CSS files to exclude from being parsed
*/
exclude?: ReadonlyArray<string | RegExp> | string | RegExp | null;
/**
* Callback that will be called ongenerate
*/
output?:
| boolean
| string
| ((
styles: string,
styleNodes: Record<string, string>,
bundle: OutputBundle
) => void)
| null
| undefined;
}
}
function css(options?: css.Options): Plugin;
export = css;
}