1import { wrapDevelopmentCSS } from './css'; 2 3const RNW_CSS_CLASS_ID = '_'; 4 5export async function transformCssModuleWeb(props: { 6 filename: string; 7 src: string; 8 options: { projectRoot: string; minify: boolean; dev: boolean; sourceMap: boolean }; 9}) { 10 const { transform } = await import('lightningcss'); 11 12 // TODO: Add bundling to resolve imports 13 // https://lightningcss.dev/bundling.html#bundling-order 14 15 const cssResults = transform({ 16 filename: props.filename, 17 code: Buffer.from(props.src), 18 sourceMap: props.options.sourceMap, 19 cssModules: { 20 // Prevent renaming CSS variables to ensure 21 // variables created in global files are available. 22 dashedIdents: false, 23 }, 24 // cssModules: true, 25 projectRoot: props.options.projectRoot, 26 minify: props.options.minify, 27 }); 28 const codeAsString = cssResults.code.toString(); 29 30 const { styles, reactNativeWeb, variables } = convertLightningCssToReactNativeWebStyleSheet( 31 cssResults.exports! 32 ); 33 34 let outputModule = `module.exports=Object.assign(${JSON.stringify( 35 styles 36 )},{unstable_styles:${JSON.stringify(reactNativeWeb)}},${JSON.stringify(variables)});`; 37 38 if (props.options.dev) { 39 const runtimeCss = wrapDevelopmentCSS({ 40 ...props, 41 src: codeAsString, 42 }); 43 44 outputModule += '\n' + runtimeCss; 45 } 46 47 return { 48 output: outputModule, 49 css: cssResults.code, 50 map: cssResults.map, 51 }; 52} 53 54export function convertLightningCssToReactNativeWebStyleSheet( 55 input: import('lightningcss').CSSModuleExports 56) { 57 const styles: Record<string, string> = {}; 58 const reactNativeWeb: Record<string, any> = {}; 59 const variables: Record<string, string> = {}; 60 // e.g. { container: { name: 'ahs8IW_container', composes: [], isReferenced: false }, } 61 Object.entries(input).map(([key, value]) => { 62 // order matters here 63 let className = value.name; 64 65 if (value.composes.length) { 66 className += ' ' + value.composes.map((value) => value.name).join(' '); 67 } 68 69 // CSS Variables will be `{string: string}` 70 if (key.startsWith('--')) { 71 variables[key] = className; 72 } 73 74 styles[key] = className; 75 reactNativeWeb[key] = { $$css: true, [RNW_CSS_CLASS_ID]: className }; 76 return { 77 [key]: { $$css: true, [RNW_CSS_CLASS_ID]: className }, 78 }; 79 }); 80 81 return { styles, reactNativeWeb, variables }; 82} 83 84export function matchCssModule(filePath: string): boolean { 85 return !!/\.module(\.(native|ios|android|web))?\.(css|s[ac]ss)$/.test(filePath); 86} 87