From d621a9f9f9b21e37130d72419e6fd70653ba0132 Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 25 Aug 2026 09:56:02 -0700 Subject: [PATCH 1/2] fix(astro): transform .astro files that arrive already compiled --- .../unplugin/__tests__/unplugin.test.js | 40 +++++++++++++++++++ packages/@stylexjs/unplugin/src/core.js | 14 ++++++- 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/packages/@stylexjs/unplugin/__tests__/unplugin.test.js b/packages/@stylexjs/unplugin/__tests__/unplugin.test.js index 4439619d2..3e67a4f33 100644 --- a/packages/@stylexjs/unplugin/__tests__/unplugin.test.js +++ b/packages/@stylexjs/unplugin/__tests__/unplugin.test.js @@ -26,6 +26,46 @@ describe('@stylexjs/unplugin', () => { expect(result).toBeNull(); }); + test('includes .astro files', () => { + const plugin = unplugin.raw({}); + expect(plugin.transformInclude('/virtual/page.astro')).toBe(true); + expect( + plugin.transformInclude('/virtual/page.astro?astro&type=script'), + ).toBe(true); + }); + + test('compiles StyleX in .astro modules', async () => { + const plugin = unplugin.rollup({ + runtimeInjection: false, + devPersistToDisk: false, + dev: false, + }); + if (typeof plugin.buildStart === 'function') { + plugin.buildStart(); + } + // Astro hands bundler plugins the compiled module, not the `---` source + const source = ` + import * as stylex from '@stylexjs/stylex'; + const styles = stylex.create({ hero: { color: 'red' } }); + export default function $$Page() { return styles; } + `; + const result = await plugin.transform(source, '/virtual/page.astro'); + expect(result).not.toBeNull(); + expect(result.code).not.toContain('stylex.create'); + + const tempDir = fs.mkdtempSync( + path.join(os.tmpdir(), 'stylex-unplugin-test-'), + ); + try { + await plugin.writeBundle({ dir: tempDir }, {}); + const cssPath = path.join(tempDir, 'assets', 'stylex.css'); + expect(fs.existsSync(cssPath)).toBe(true); + expect(fs.readFileSync(cssPath, 'utf8')).toContain('color: red;'); + } finally { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + }); + test('writes fallback CSS asset when no CSS bundle entry exists', async () => { const plugin = unplugin.rollup({ runtimeInjection: false, diff --git a/packages/@stylexjs/unplugin/src/core.js b/packages/@stylexjs/unplugin/src/core.js index 340af13cf..3fdb8a0e9 100644 --- a/packages/@stylexjs/unplugin/src/core.js +++ b/packages/@stylexjs/unplugin/src/core.js @@ -210,6 +210,9 @@ function discoverStylexPackages({ const JS_LIKE_RE = /\.[cm]?[jt]sx?(\?|$)/; const SVELTE_LIKE_RE = /\.svelte(\?|$)/; +// Astro compiles `.astro` to JavaScript before any bundler plugin runs, so these +// arrive here as plain modules and are handled like any other JS-like file. +const ASTRO_LIKE_RE = /\.astro(\?|$)/; export const unpluginFactory = (userOptions = {}, metaOptions) => { // framework :: 'rollup' | 'vite' | 'rolldown' | 'farm' | 'unloader' @@ -406,13 +409,20 @@ export const unpluginFactory = (userOptions = {}, metaOptions) => { }, transformInclude(id) { - return JS_LIKE_RE.test(id) || SVELTE_LIKE_RE.test(id); + return ( + JS_LIKE_RE.test(id) || SVELTE_LIKE_RE.test(id) || ASTRO_LIKE_RE.test(id) + ); }, // Core code transform async transform(code, id) { // Only handle JS-like files; avoid parsing CSS/JSON/etc - if (!JS_LIKE_RE.test(id) && !SVELTE_LIKE_RE.test(id)) return null; + if ( + !JS_LIKE_RE.test(id) && + !SVELTE_LIKE_RE.test(id) && + !ASTRO_LIKE_RE.test(id) + ) + return null; if (!shouldHandle(code)) return null; // Extract the pure filename by removing everything after '?' (e.g., handling Vite's '?v=' cache busting). From c7acb8d852b448c2f6b28c8e9b45e5cf8db5dfde Mon Sep 17 00:00:00 2001 From: wobsoriano Date: Tue, 25 Aug 2026 10:07:04 -0700 Subject: [PATCH 2/2] chore: clean up --- .../unplugin/__tests__/unplugin.test.js | 2 +- packages/@stylexjs/unplugin/src/core.js | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/@stylexjs/unplugin/__tests__/unplugin.test.js b/packages/@stylexjs/unplugin/__tests__/unplugin.test.js index 3e67a4f33..c4054bd5f 100644 --- a/packages/@stylexjs/unplugin/__tests__/unplugin.test.js +++ b/packages/@stylexjs/unplugin/__tests__/unplugin.test.js @@ -47,7 +47,7 @@ describe('@stylexjs/unplugin', () => { const source = ` import * as stylex from '@stylexjs/stylex'; const styles = stylex.create({ hero: { color: 'red' } }); - export default function $$Page() { return styles; } + export default styles; `; const result = await plugin.transform(source, '/virtual/page.astro'); expect(result).not.toBeNull(); diff --git a/packages/@stylexjs/unplugin/src/core.js b/packages/@stylexjs/unplugin/src/core.js index 3fdb8a0e9..2d9ab8409 100644 --- a/packages/@stylexjs/unplugin/src/core.js +++ b/packages/@stylexjs/unplugin/src/core.js @@ -210,10 +210,14 @@ function discoverStylexPackages({ const JS_LIKE_RE = /\.[cm]?[jt]sx?(\?|$)/; const SVELTE_LIKE_RE = /\.svelte(\?|$)/; -// Astro compiles `.astro` to JavaScript before any bundler plugin runs, so these -// arrive here as plain modules and are handled like any other JS-like file. const ASTRO_LIKE_RE = /\.astro(\?|$)/; +function isTransformableId(id) { + return ( + JS_LIKE_RE.test(id) || SVELTE_LIKE_RE.test(id) || ASTRO_LIKE_RE.test(id) + ); +} + export const unpluginFactory = (userOptions = {}, metaOptions) => { // framework :: 'rollup' | 'vite' | 'rolldown' | 'farm' | 'unloader' const framework = metaOptions?.framework; @@ -409,20 +413,13 @@ export const unpluginFactory = (userOptions = {}, metaOptions) => { }, transformInclude(id) { - return ( - JS_LIKE_RE.test(id) || SVELTE_LIKE_RE.test(id) || ASTRO_LIKE_RE.test(id) - ); + return isTransformableId(id); }, // Core code transform async transform(code, id) { // Only handle JS-like files; avoid parsing CSS/JSON/etc - if ( - !JS_LIKE_RE.test(id) && - !SVELTE_LIKE_RE.test(id) && - !ASTRO_LIKE_RE.test(id) - ) - return null; + if (!isTransformableId(id)) return null; if (!shouldHandle(code)) return null; // Extract the pure filename by removing everything after '?' (e.g., handling Vite's '?v=' cache busting).