import { dirname, join } from "node:path"; import type * as esbuild from "esbuild"; import { CssSyntaxError } from "postcss"; import { type Compile, type StyleMap, pkgName, toCSSText } from "./shared"; const PLUGIN_NAME = "tailwind"; const ESBUILD_NAMESPACE = "babel-tailwind"; export const esbuildPlugin = (styleMap: StyleMap, compile: Compile): esbuild.Plugin => ({ name: PLUGIN_NAME, setup(build) { build.onResolve({ filter: /^tailwind:.+\.css$/ }, ({ path, importer }) => { const resolved = join(dirname(importer), path.replace(/^tailwind:/, "")); if (styleMap.has(resolved)) { return { path: resolved, namespace: ESBUILD_NAMESPACE, }; } }); build.onResolve({ filter: RegExp(`^${pkgName}/base$`) }, () => ({ path: "directive:base", namespace: ESBUILD_NAMESPACE, })); build.onLoad({ filter: /.*/, namespace: ESBUILD_NAMESPACE }, async ({ path }) => { if (path === "directive:base") { return { contents: (await compile("@tailwind base")).css, loader: "css", }; } if (!styleMap.has(path)) return; const styles = styleMap.get(path)!; try { const result = await compile(toCSSText(styles)); return { contents: result.css, loader: "css", }; } catch (e) { if (e instanceof CssSyntaxError) { const lines = e.source!.split("\n"); const cls = lines .at(e.line! - 2)! .slice(1, -1) .trim(); const entry = styles.find(s => s.key === cls)!; if (!entry) { throw new Error("Could not find entry for CSS"); } const { location: loc } = entry; const errLoc: Partial = { file: loc.filename, line: loc.start.line, column: loc.start.column, length: loc.end.column - loc.start.column, lineText: loc.text, }; const doesNotExist = e.reason.match(/The `(.+)` class does not exist/)?.[1]; if (doesNotExist) { const index = loc.text.indexOf(doesNotExist, loc.start.column); if (index !== -1) { errLoc.column = index; errLoc.length = doesNotExist.length; } } return { errors: [ { text: e.reason, location: errLoc, }, ], }; } throw e; } }); }, });