@fastkit/plugboy-vanilla-extract-plugin 4.0.0-next.11 → 4.0.0-next.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,14 +56,31 @@ async function createVanillaExtractPlugin(options = {}) {
56
56
  return opts;
57
57
  },
58
58
  generateBundle(_options, bundle) {
59
+ const collectEntryCss = (root) => {
60
+ const visited = /* @__PURE__ */ new Set();
61
+ const seenCss = /* @__PURE__ */ new Set();
62
+ const out = [];
63
+ const walk = (id) => {
64
+ if (visited.has(id)) return;
65
+ visited.add(id);
66
+ const info = this.getModuleInfo(id);
67
+ if (!info) return;
68
+ for (const dep of info.importedIds ?? []) {
69
+ const css = this.getModuleInfo(dep)?.meta?.css;
70
+ if (typeof css === "string" && !seenCss.has(dep)) {
71
+ seenCss.add(dep);
72
+ out.push(css);
73
+ }
74
+ walk(dep);
75
+ }
76
+ };
77
+ walk(root);
78
+ return out;
79
+ };
59
80
  const entryCss = [];
60
81
  for (const chunk of Object.values(bundle)) {
61
- if (chunk.type !== "chunk" || !chunk.isEntry || !chunk.fileName.endsWith(".mjs")) continue;
62
- const cssChunks = [];
63
- for (const importId of chunk.imports) {
64
- const css = this.getModuleInfo(importId)?.meta?.css;
65
- if (typeof css === "string") cssChunks.push(css);
66
- }
82
+ if (chunk.type !== "chunk" || !chunk.isEntry || !chunk.fileName.endsWith(".mjs") || !chunk.facadeModuleId) continue;
83
+ const cssChunks = collectEntryCss(chunk.facadeModuleId);
67
84
  if (cssChunks.length) entryCss.push({
68
85
  name: chunk.name,
69
86
  source: cssChunks.join("\n")
@@ -1 +1 @@
1
- {"version":3,"file":"plugboy-vanilla-extract-plugin.mjs","names":["vanillaExtractPlugin"],"sources":["../src/types.ts","../src/plugin.ts","../src/vite.ts"],"sourcesContent":["import { Plugin } from '@fastkit/plugboy';\nimport type { vanillaExtractPlugin as rollupPlugin } from '@vanilla-extract/rollup-plugin';\n\ntype VanillaExtractPluginOptions = Omit<\n NonNullable<Parameters<typeof rollupPlugin>[0]>,\n 'extract'\n>;\n\nexport type PluginOptions = Pick<\n VanillaExtractPluginOptions,\n 'identifiers' | 'esbuildOptions'\n>;\n\nexport const PLUGIN_NAME = 'plugboy-vanilla-extract';\n\nexport interface VanillaExtractPlugin extends Plugin {\n name: typeof PLUGIN_NAME;\n _options: PluginOptions;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { definePlugin, findFile, type Plugin } from '@fastkit/plugboy';\nimport { vanillaExtractPlugin } from '@vanilla-extract/rollup-plugin';\nimport { VanillaExtractPlugin, PluginOptions, PLUGIN_NAME } from './types';\n\ndeclare module '@fastkit/plugboy' {\n export interface WorkspaceMeta {\n hasVanillaExtract: boolean;\n }\n}\n\n/**\n * Temporary file name for the CSS that tsdown's own CSS pipeline emits.\n *\n * A package can have two independent sources of CSS:\n * - tsdown's built-in CSS handling, for plain `.css` / `.scss` imports.\n * - `@vanilla-extract/rollup-plugin`, for `.css.ts` files (extracted into a\n * single bundle named after the package).\n *\n * If both are pointed at the same final file name they collide\n * (`FILE_NAME_CONFLICT` — one silently overwrites the other, dropping all of\n * the vanilla-extract component CSS). To avoid that we route tsdown's CSS to\n * this temporary name and merge it into the vanilla-extract bundle in\n * `writeBundle`.\n */\nconst TSDOWN_CSS_FILE_NAME = '__ve-tsdown__.css';\n\nexport async function createVanillaExtractPlugin(options: PluginOptions = {}) {\n return definePlugin<VanillaExtractPlugin>({\n name: PLUGIN_NAME,\n _options: options,\n hooks: {\n async setupWorkspace(ctx, getWorkspace) {\n // Derive the final CSS file name from the workspace entry, mirroring the\n // way plugboy names the JS output: the main entry (`.`) maps to the\n // package directory name (e.g. `vue-app-layout`), other entries keep\n // their id. Since `splitting: false` produces a single combined CSS for\n // the package, we base it on the main entry (falling back to the first).\n // Result: `dist/vue-app-layout.css` instead of `dist/__ve-tmp__.css`.\n const entryIds = Object.keys(ctx.config.entries);\n const cssBaseName = entryIds.includes('.')\n ? ctx.dir.basename\n : (entryIds[0] ?? ctx.dir.basename);\n const cssFileName = `${cssBaseName}.css`;\n\n ctx.mergeExternals(/@vanilla-extract/);\n\n ctx.meta.hasVanillaExtract = !!(await findFile(\n ctx.dirs.src.value,\n /\\.css\\.ts$/,\n ));\n\n // When vanilla-extract is in play, route tsdown's own CSS to a temporary\n // name so it doesn't collide with the vanilla-extract bundle that also\n // targets `cssFileName`; the two are merged into a single `cssFileName`\n // by the `writeBundle` hook below. Without vanilla-extract there is no\n // second producer, so tsdown emits `cssFileName` directly.\n ctx.css = {\n splitting: false,\n fileName: ctx.meta.hasVanillaExtract\n ? TSDOWN_CSS_FILE_NAME\n : cssFileName,\n };\n\n if (ctx.meta.hasVanillaExtract) {\n const originalPlugin = vanillaExtractPlugin({\n ...options,\n extract: {\n name: cssFileName,\n sourcemap: false,\n },\n });\n\n // `@vanilla-extract/rollup-plugin` returns a rollup `Plugin`, but\n // plugboy's `ctx.plugins` expects a tsdown (rolldown) `Plugin`. The two\n // are structurally almost identical, but hooks like `outputOptions`\n // type `this` as rollup's `PluginContext` vs rolldown's\n // `MinimalPluginContext`, which makes them unassignable (the `this`\n // type is contravariant). rolldown accepts rollup plugins at runtime,\n // so this is harmless — cast to work around the type mismatch.\n ctx.plugins.push(originalPlugin as unknown as Plugin);\n\n // `@vanilla-extract/rollup-plugin` emits the extracted CSS via\n // `emitFile({ type: 'asset', name: cssFileName })`. Because it uses\n // `name` (a hint) rather than `fileName`, rolldown runs it through the\n // default `assetFileNames` pattern (`assets/[name]-[hash][extname]`),\n // producing e.g. `dist/assets/vue-app-layout-dry0z-1l.css`.\n //\n // We can't *rename* an asset in `generateBundle` because rolldown\n // ignores mutations to a bundle entry's `fileName`. Instead, override\n // `assetFileNames` via the `outputOptions` hook so this single CSS\n // asset keeps its derived name verbatim (no hash, no `assets/` dir)\n // while every other asset keeps its original naming.\n ctx.plugins.push({\n name: `${PLUGIN_NAME}:rename-css`,\n outputOptions(opts) {\n const original = opts.assetFileNames;\n opts.assetFileNames = (assetInfo) => {\n if (assetInfo.names.includes(cssFileName)) {\n return cssFileName;\n }\n if (typeof original === 'function') return original(assetInfo);\n return original ?? 'assets/[name]-[hash][extname]';\n };\n return opts;\n },\n // Split vanilla-extract's single bundle into one CSS file per entry.\n //\n // `extract: { name }` mode collects the CSS of EVERY `.css.ts` in the\n // graph into one asset (`cssFileName`), which loses plugboy's per-entry\n // CSS contract: every entry with `css: true` declares a `./<entry>.css`\n // export, but only `cssFileName` is ever produced. We rebuild the\n // per-entry files from data vanilla-extract already exposes:\n // `moduleInfo.meta.css` (its public hand-off for extracted CSS, the\n // same field its own bundler reads) keyed by each entry chunk's\n // `imports`. We never parse vanilla-extract's asset names or re-add the\n // import statements it strips, so the only coupling is `meta.css`.\n //\n // Runs before `plugboy-optimize-css` (appended later in\n // `workspace.plugins`), so each emitted per-entry file still goes\n // through the postcss optimizations.\n //\n // Only splits when more than one entry actually has CSS. With a single\n // CSS entry (the common case) vanilla-extract's bundle is already the\n // correct, fully-ordered output, so it is left untouched and existing\n // single-entry packages are byte-for-byte unaffected.\n generateBundle(_options, bundle) {\n const entryCss: { name: string; source: string }[] = [];\n\n for (const chunk of Object.values(bundle)) {\n if (\n chunk.type !== 'chunk' ||\n !chunk.isEntry ||\n !chunk.fileName.endsWith('.mjs')\n ) {\n continue;\n }\n const cssChunks: string[] = [];\n for (const importId of chunk.imports) {\n const css = this.getModuleInfo(importId)?.meta?.css;\n if (typeof css === 'string') cssChunks.push(css);\n }\n if (cssChunks.length) {\n entryCss.push({\n name: chunk.name,\n source: cssChunks.join('\\n'),\n });\n }\n }\n\n // 0 or 1 CSS entry → vanilla-extract's bundle is already correct.\n if (entryCss.length <= 1) return;\n\n // Replace vanilla-extract's combined bundle with per-entry files.\n // The entry whose file name matches `cssFileName` overwrites the\n // existing asset in place — re-`emitFile`ing the same name would\n // trip rolldown's FILE_NAME_CONFLICT, since deleting the bundle\n // entry does not release the reserved file name. Other entries are\n // emitted as new assets.\n const reused = new Set<string>();\n for (const { name, source } of entryCss) {\n const fileName = `${name}.css`;\n const existing = bundle[fileName];\n if (existing && existing.type === 'asset') {\n existing.source = source;\n reused.add(fileName);\n } else {\n this.emitFile({ type: 'asset', fileName, source });\n }\n }\n\n // Drop vanilla-extract's combined bundle if no entry reused it.\n const combined = bundle[cssFileName];\n if (\n combined &&\n combined.type === 'asset' &&\n !reused.has(cssFileName)\n ) {\n delete bundle[cssFileName];\n }\n },\n // Merge tsdown's own CSS (emitted to `TSDOWN_CSS_FILE_NAME`) into the\n // vanilla-extract bundle so the package ships a single `cssFileName`.\n //\n // This has to happen in `writeBundle`, not `generateBundle`: tsdown\n // emits its CSS in a separate output pass, so `TSDOWN_CSS_FILE_NAME`\n // is absent from the bundle our `generateBundle` sees but present\n // (alongside the vanilla-extract asset) by `writeBundle`. By then both\n // files are already on disk, so we merge on disk rather than mutating\n // bundle sources. tsdown's CSS goes first so its `@layer` declarations\n // / resets are established before the extracted component styles.\n async writeBundle(outputOptions, bundle) {\n // Only the output pass that emitted tsdown's CSS performs the merge\n // (it is the one whose `bundle` contains `TSDOWN_CSS_FILE_NAME`).\n // This also prevents a second output from re-injecting the imports.\n const tmp = bundle[TSDOWN_CSS_FILE_NAME];\n if (!tmp) return;\n\n const tmpCss = tmp.type === 'asset' ? tmp.source.toString() : '';\n const dir = outputOptions.dir ?? '.';\n const tmpPath = path.join(dir, TSDOWN_CSS_FILE_NAME);\n const targetPath = path.join(dir, cssFileName);\n\n let targetCss = '';\n try {\n targetCss = await fs.readFile(targetPath, 'utf8');\n } catch {\n // No vanilla-extract output file (e.g. `.css.ts` produced no\n // rules) — tsdown's CSS becomes the whole `cssFileName`.\n }\n\n const merged = tmpCss\n ? targetCss\n ? `${tmpCss}\\n${targetCss}`\n : tmpCss\n : targetCss;\n\n if (merged) await fs.writeFile(targetPath, merged);\n await fs.rm(tmpPath, { force: true });\n },\n });\n }\n },\n },\n });\n}\n","import { findProjectPlugin } from '@fastkit/plugboy';\nimport { Plugin as VitePlugin } from 'vite';\nimport { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';\nimport { PLUGIN_NAME, VanillaExtractPlugin } from './types';\n\ntype VanillaExtractVitePluginOptions = NonNullable<\n Parameters<typeof vanillaExtractPlugin>[0]\n>;\n\nexport interface ViteVanillaExtractPluginOptions extends VanillaExtractVitePluginOptions {}\n\nexport async function ViteVanillaExtractPlugin(\n options: ViteVanillaExtractPluginOptions = {},\n): Promise<VitePlugin[]> {\n const plugin = await findProjectPlugin<VanillaExtractPlugin>(PLUGIN_NAME);\n const { identifiers: baseIdentifiers } = plugin?._options || {};\n\n return [\n ...vanillaExtractPlugin({\n identifiers: baseIdentifiers,\n ...options,\n }),\n // @MEMO\n // Plugin to prevent file scope mismatches when utilities using vanilla-extract\n // functions are placed in external files\n {\n name: 'vanilla-extract-fix-file-scope',\n config(viteConfig) {\n viteConfig.resolve ??= {};\n viteConfig.resolve.dedupe ??= [];\n viteConfig.resolve.dedupe.push(\n '@vanilla-extract/css',\n '@vanilla-extract/css/fileScope',\n );\n },\n },\n ];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"plugboy-vanilla-extract-plugin.mjs","names":["vanillaExtractPlugin"],"sources":["../src/types.ts","../src/plugin.ts","../src/vite.ts"],"sourcesContent":["import { Plugin } from '@fastkit/plugboy';\nimport type { vanillaExtractPlugin as rollupPlugin } from '@vanilla-extract/rollup-plugin';\n\ntype VanillaExtractPluginOptions = Omit<\n NonNullable<Parameters<typeof rollupPlugin>[0]>,\n 'extract'\n>;\n\nexport type PluginOptions = Pick<\n VanillaExtractPluginOptions,\n 'identifiers' | 'esbuildOptions'\n>;\n\nexport const PLUGIN_NAME = 'plugboy-vanilla-extract';\n\nexport interface VanillaExtractPlugin extends Plugin {\n name: typeof PLUGIN_NAME;\n _options: PluginOptions;\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { definePlugin, findFile, type Plugin } from '@fastkit/plugboy';\nimport { vanillaExtractPlugin } from '@vanilla-extract/rollup-plugin';\nimport { VanillaExtractPlugin, PluginOptions, PLUGIN_NAME } from './types';\n\ndeclare module '@fastkit/plugboy' {\n export interface WorkspaceMeta {\n hasVanillaExtract: boolean;\n }\n}\n\n/**\n * Temporary file name for the CSS that tsdown's own CSS pipeline emits.\n *\n * A package can have two independent sources of CSS:\n * - tsdown's built-in CSS handling, for plain `.css` / `.scss` imports.\n * - `@vanilla-extract/rollup-plugin`, for `.css.ts` files (extracted into a\n * single bundle named after the package).\n *\n * If both are pointed at the same final file name they collide\n * (`FILE_NAME_CONFLICT` — one silently overwrites the other, dropping all of\n * the vanilla-extract component CSS). To avoid that we route tsdown's CSS to\n * this temporary name and merge it into the vanilla-extract bundle in\n * `writeBundle`.\n */\nconst TSDOWN_CSS_FILE_NAME = '__ve-tsdown__.css';\n\nexport async function createVanillaExtractPlugin(options: PluginOptions = {}) {\n return definePlugin<VanillaExtractPlugin>({\n name: PLUGIN_NAME,\n _options: options,\n hooks: {\n async setupWorkspace(ctx, getWorkspace) {\n // Derive the final CSS file name from the workspace entry, mirroring the\n // way plugboy names the JS output: the main entry (`.`) maps to the\n // package directory name (e.g. `vue-app-layout`), other entries keep\n // their id. Since `splitting: false` produces a single combined CSS for\n // the package, we base it on the main entry (falling back to the first).\n // Result: `dist/vue-app-layout.css` instead of `dist/__ve-tmp__.css`.\n const entryIds = Object.keys(ctx.config.entries);\n const cssBaseName = entryIds.includes('.')\n ? ctx.dir.basename\n : (entryIds[0] ?? ctx.dir.basename);\n const cssFileName = `${cssBaseName}.css`;\n\n ctx.mergeExternals(/@vanilla-extract/);\n\n ctx.meta.hasVanillaExtract = !!(await findFile(\n ctx.dirs.src.value,\n /\\.css\\.ts$/,\n ));\n\n // When vanilla-extract is in play, route tsdown's own CSS to a temporary\n // name so it doesn't collide with the vanilla-extract bundle that also\n // targets `cssFileName`; the two are merged into a single `cssFileName`\n // by the `writeBundle` hook below. Without vanilla-extract there is no\n // second producer, so tsdown emits `cssFileName` directly.\n ctx.css = {\n splitting: false,\n fileName: ctx.meta.hasVanillaExtract\n ? TSDOWN_CSS_FILE_NAME\n : cssFileName,\n };\n\n if (ctx.meta.hasVanillaExtract) {\n const originalPlugin = vanillaExtractPlugin({\n ...options,\n extract: {\n name: cssFileName,\n sourcemap: false,\n },\n });\n\n // `@vanilla-extract/rollup-plugin` returns a rollup `Plugin`, but\n // plugboy's `ctx.plugins` expects a tsdown (rolldown) `Plugin`. The two\n // are structurally almost identical, but hooks like `outputOptions`\n // type `this` as rollup's `PluginContext` vs rolldown's\n // `MinimalPluginContext`, which makes them unassignable (the `this`\n // type is contravariant). rolldown accepts rollup plugins at runtime,\n // so this is harmless — cast to work around the type mismatch.\n ctx.plugins.push(originalPlugin as unknown as Plugin);\n\n // `@vanilla-extract/rollup-plugin` emits the extracted CSS via\n // `emitFile({ type: 'asset', name: cssFileName })`. Because it uses\n // `name` (a hint) rather than `fileName`, rolldown runs it through the\n // default `assetFileNames` pattern (`assets/[name]-[hash][extname]`),\n // producing e.g. `dist/assets/vue-app-layout-dry0z-1l.css`.\n //\n // We can't *rename* an asset in `generateBundle` because rolldown\n // ignores mutations to a bundle entry's `fileName`. Instead, override\n // `assetFileNames` via the `outputOptions` hook so this single CSS\n // asset keeps its derived name verbatim (no hash, no `assets/` dir)\n // while every other asset keeps its original naming.\n ctx.plugins.push({\n name: `${PLUGIN_NAME}:rename-css`,\n outputOptions(opts) {\n const original = opts.assetFileNames;\n opts.assetFileNames = (assetInfo) => {\n if (assetInfo.names.includes(cssFileName)) {\n return cssFileName;\n }\n if (typeof original === 'function') return original(assetInfo);\n return original ?? 'assets/[name]-[hash][extname]';\n };\n return opts;\n },\n // Split vanilla-extract's single bundle into one CSS file per entry.\n //\n // `extract: { name }` mode collects the CSS of EVERY `.css.ts` in the\n // graph into one asset (`cssFileName`), which loses plugboy's per-entry\n // CSS contract: every entry with `css: true` declares a `./<entry>.css`\n // export, but only `cssFileName` is ever produced. We rebuild the\n // per-entry files from data vanilla-extract already exposes:\n // `moduleInfo.meta.css` (its public hand-off for extracted CSS, the\n // same field its own bundler reads).\n //\n // CSS is attributed to an entry by walking the INPUT module graph from\n // that entry's `facadeModuleId` via `getModuleInfo().importedIds`, NOT\n // by reading the output chunk's `imports`. `chunk.imports` lists output\n // chunk file names plus external ids, and whether vanilla-extract's\n // external virtual CSS ids appear there is rolldown-version-dependent\n // (some versions only list real output chunks, so the lookup finds\n // nothing and the split silently no-ops). The input graph is stable: it\n // always yields the `.css.ts` modules an entry reaches, regardless of\n // how rolldown chunks the output. A `.css.ts` shared by several entries\n // is included in each entry's file (self-contained per-entry CSS).\n //\n // We never parse vanilla-extract's asset names or re-add the import\n // statements it strips, so the only coupling is `meta.css`.\n //\n // Runs before `plugboy-optimize-css` (appended later in\n // `workspace.plugins`), so each emitted per-entry file still goes\n // through the postcss optimizations.\n //\n // Only splits when more than one entry actually has CSS. With a single\n // CSS entry (the common case) vanilla-extract's bundle is already the\n // correct, fully-ordered output, so it is left untouched and existing\n // single-entry packages are byte-for-byte unaffected.\n generateBundle(_options, bundle) {\n // Collect, in import order, the CSS of every `.css.ts` reachable\n // from `root` through the input module graph (deduped per entry).\n const collectEntryCss = (root: string): string[] => {\n const visited = new Set<string>();\n const seenCss = new Set<string>();\n const out: string[] = [];\n const walk = (id: string) => {\n if (visited.has(id)) return;\n visited.add(id);\n const info = this.getModuleInfo(id);\n if (!info) return;\n for (const dep of info.importedIds ?? []) {\n const css = this.getModuleInfo(dep)?.meta?.css;\n if (typeof css === 'string' && !seenCss.has(dep)) {\n seenCss.add(dep);\n out.push(css);\n }\n walk(dep);\n }\n };\n walk(root);\n return out;\n };\n\n const entryCss: { name: string; source: string }[] = [];\n\n for (const chunk of Object.values(bundle)) {\n if (\n chunk.type !== 'chunk' ||\n !chunk.isEntry ||\n !chunk.fileName.endsWith('.mjs') ||\n !chunk.facadeModuleId\n ) {\n continue;\n }\n const cssChunks = collectEntryCss(chunk.facadeModuleId);\n if (cssChunks.length) {\n entryCss.push({\n name: chunk.name,\n source: cssChunks.join('\\n'),\n });\n }\n }\n\n // 0 or 1 CSS entry → vanilla-extract's bundle is already correct.\n if (entryCss.length <= 1) return;\n\n // Replace vanilla-extract's combined bundle with per-entry files.\n // The entry whose file name matches `cssFileName` overwrites the\n // existing asset in place — re-`emitFile`ing the same name would\n // trip rolldown's FILE_NAME_CONFLICT, since deleting the bundle\n // entry does not release the reserved file name. Other entries are\n // emitted as new assets.\n const reused = new Set<string>();\n for (const { name, source } of entryCss) {\n const fileName = `${name}.css`;\n const existing = bundle[fileName];\n if (existing && existing.type === 'asset') {\n existing.source = source;\n reused.add(fileName);\n } else {\n this.emitFile({ type: 'asset', fileName, source });\n }\n }\n\n // Drop vanilla-extract's combined bundle if no entry reused it.\n const combined = bundle[cssFileName];\n if (\n combined &&\n combined.type === 'asset' &&\n !reused.has(cssFileName)\n ) {\n delete bundle[cssFileName];\n }\n },\n // Merge tsdown's own CSS (emitted to `TSDOWN_CSS_FILE_NAME`) into the\n // vanilla-extract bundle so the package ships a single `cssFileName`.\n //\n // This has to happen in `writeBundle`, not `generateBundle`: tsdown\n // emits its CSS in a separate output pass, so `TSDOWN_CSS_FILE_NAME`\n // is absent from the bundle our `generateBundle` sees but present\n // (alongside the vanilla-extract asset) by `writeBundle`. By then both\n // files are already on disk, so we merge on disk rather than mutating\n // bundle sources. tsdown's CSS goes first so its `@layer` declarations\n // / resets are established before the extracted component styles.\n async writeBundle(outputOptions, bundle) {\n // Only the output pass that emitted tsdown's CSS performs the merge\n // (it is the one whose `bundle` contains `TSDOWN_CSS_FILE_NAME`).\n // This also prevents a second output from re-injecting the imports.\n const tmp = bundle[TSDOWN_CSS_FILE_NAME];\n if (!tmp) return;\n\n const tmpCss = tmp.type === 'asset' ? tmp.source.toString() : '';\n const dir = outputOptions.dir ?? '.';\n const tmpPath = path.join(dir, TSDOWN_CSS_FILE_NAME);\n const targetPath = path.join(dir, cssFileName);\n\n let targetCss = '';\n try {\n targetCss = await fs.readFile(targetPath, 'utf8');\n } catch {\n // No vanilla-extract output file (e.g. `.css.ts` produced no\n // rules) — tsdown's CSS becomes the whole `cssFileName`.\n }\n\n const merged = tmpCss\n ? targetCss\n ? `${tmpCss}\\n${targetCss}`\n : tmpCss\n : targetCss;\n\n if (merged) await fs.writeFile(targetPath, merged);\n await fs.rm(tmpPath, { force: true });\n },\n });\n }\n },\n },\n });\n}\n","import { findProjectPlugin } from '@fastkit/plugboy';\nimport { Plugin as VitePlugin } from 'vite';\nimport { vanillaExtractPlugin } from '@vanilla-extract/vite-plugin';\nimport { PLUGIN_NAME, VanillaExtractPlugin } from './types';\n\ntype VanillaExtractVitePluginOptions = NonNullable<\n Parameters<typeof vanillaExtractPlugin>[0]\n>;\n\nexport interface ViteVanillaExtractPluginOptions extends VanillaExtractVitePluginOptions {}\n\nexport async function ViteVanillaExtractPlugin(\n options: ViteVanillaExtractPluginOptions = {},\n): Promise<VitePlugin[]> {\n const plugin = await findProjectPlugin<VanillaExtractPlugin>(PLUGIN_NAME);\n const { identifiers: baseIdentifiers } = plugin?._options || {};\n\n return [\n ...vanillaExtractPlugin({\n identifiers: baseIdentifiers,\n ...options,\n }),\n // @MEMO\n // Plugin to prevent file scope mismatches when utilities using vanilla-extract\n // functions are placed in external files\n {\n name: 'vanilla-extract-fix-file-scope',\n config(viteConfig) {\n viteConfig.resolve ??= {};\n viteConfig.resolve.dedupe ??= [];\n viteConfig.resolve.dedupe.push(\n '@vanilla-extract/css',\n '@vanilla-extract/css/fileScope',\n );\n },\n },\n ];\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastkit/plugboy-vanilla-extract-plugin",
3
- "version": "4.0.0-next.11",
3
+ "version": "4.0.0-next.12",
4
4
  "description": "",
5
5
  "keywords": [],
6
6
  "repository": {