diff --git a/CONTEXT.md b/CONTEXT.md index f3ca4ab4..b7b15809 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -117,7 +117,8 @@ Metro integration: - `withUniwindConfig(config, uniwindConfig)` patches Metro graph support for uncached modules. - Metro adds `css` as source extension and removes it from asset extensions. -- Metro transformer handles the configured CSS entry file specially. +- Metro transformer handles the configured CSS entry file specially. In development, native entries declare imported local CSS files as Metro dependencies, including nested imports and workspace files resolved outside `node_modules`, so token-only edits trigger recompilation. Dependencies are collected afresh on each compile. +- Non-entry native CSS is an empty module in plain Metro; Expo keeps its own CSS handling. Web CSS handling is unchanged. - Metro transformer worker selection is lazy, cached per Expo/non-Expo config type, and follows Expo transformer paths or Expo-specific config markers. - Native platform CSS transforms into a JS module that calls `Uniwind.__reinit(...)` with a fingerprint of the generated styles and themes. During development, the native runtime skips reinitialization when that fingerprint is unchanged. - Web platform CSS transforms into CSS plus web runtime setup. diff --git a/packages/uniwind/src/bundler/adapters/metro/transformer.ts b/packages/uniwind/src/bundler/adapters/metro/transformer.ts index da6a0352..94c8de5a 100644 --- a/packages/uniwind/src/bundler/adapters/metro/transformer.ts +++ b/packages/uniwind/src/bundler/adapters/metro/transformer.ts @@ -63,13 +63,28 @@ export const transform = async ( } if (!isCss) { + if (!config.uniwind.isExpoProject && options.platform !== Platform.Web && options.type !== 'asset' && filePath.endsWith('.css')) { + // Plain Metro parses CSS as JavaScript; these modules only register watched files. + return worker.transform(config, projectRoot, `${filePath}.js`, Buffer.from(''), options) + } + return worker.transform(config, projectRoot, filePath, data, options) } const bundlerConfig = UniwindBundlerConfig.fromMetroConfig(config.uniwind, options.platform) await bundlerConfig.generateArtifacts(cssArtifactPath) - const virtualCode = await compileCSS(bundlerConfig) const isWeb = bundlerConfig.platform === Platform.Web + const importedStylesheets = new Set() + const virtualCode = await compileCSS(bundlerConfig, dependency => { + if (!isWeb && options.dev && dependency.endsWith('.css') && !dependency.includes(`${path.sep}node_modules${path.sep}`)) { + importedStylesheets.add(dependency) + } + }) + const importedStylesheetRequires = Array.from(importedStylesheets).sort().map(stylesheet => { + const relativePath = path.relative(path.dirname(bundlerConfig.cssPath), stylesheet).split(path.sep).join('/') + + return `require(${JSON.stringify(relativePath.startsWith('../') ? relativePath : `./${relativePath}`)});` + }) const nativeStylesFingerprint = isWeb ? undefined : createHash('sha256') @@ -82,6 +97,7 @@ export const transform = async ( isWeb ? virtualCode : [ + ...importedStylesheetRequires, `const { Uniwind } = require('uniwind');`, `Uniwind.__reinit(rt => ${virtualCode}, ${bundlerConfig.stringifiedThemes}, '${nativeStylesFingerprint}');`, ].join(''), diff --git a/packages/uniwind/src/bundler/css-compiler/compileCSS.ts b/packages/uniwind/src/bundler/css-compiler/compileCSS.ts index bc3e7566..0853a1c6 100644 --- a/packages/uniwind/src/bundler/css-compiler/compileCSS.ts +++ b/packages/uniwind/src/bundler/css-compiler/compileCSS.ts @@ -4,8 +4,8 @@ import { compileNativeCSS } from './compileNativeCSS' import { compileTailwind } from './compileTailwind' import { compileWebCSS } from './compileWebCSS' -export const compileCSS = async (bundlerConfig: UniwindBundlerConfig) => { - const tailwindCSS = await compileTailwind(bundlerConfig) +export const compileCSS = async (bundlerConfig: UniwindBundlerConfig, onDependency?: (dependency: string) => void) => { + const tailwindCSS = await compileTailwind(bundlerConfig, onDependency) if (bundlerConfig.platform === Platform.Web) { return compileWebCSS(bundlerConfig, tailwindCSS) diff --git a/packages/uniwind/src/bundler/css-compiler/compileTailwind.ts b/packages/uniwind/src/bundler/css-compiler/compileTailwind.ts index 402c2ea3..2bf9cf6b 100644 --- a/packages/uniwind/src/bundler/css-compiler/compileTailwind.ts +++ b/packages/uniwind/src/bundler/css-compiler/compileTailwind.ts @@ -4,11 +4,14 @@ import fs from 'fs' import path from 'path' import type { UniwindBundlerConfig } from '../config' -export const compileTailwind = async (bundlerConfig: UniwindBundlerConfig) => { +export const compileTailwind = async ( + bundlerConfig: UniwindBundlerConfig, + onDependency: (dependency: string) => void = () => void 0, +) => { const css = await fs.promises.readFile(bundlerConfig.cssPath, 'utf-8') const compiler = await compile(css, { base: path.dirname(bundlerConfig.cssPath), - onDependency: () => void 0, + onDependency, }) const scanner = new Scanner({ sources: [