From c7b03776eee9631aa02f106e3af307fb354d753c Mon Sep 17 00:00:00 2001 From: Drew Powers <1369770+drwpow@users.noreply.github.com> Date: Fri, 26 Mar 2021 13:26:36 -0600 Subject: [PATCH] Fix JSX CSS Modules classes (#31) --- examples/snowpack/astro/pages/index.astro | 2 +- src/compiler/optimize/styles.ts | 29 +++++++++++++---------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/snowpack/astro/pages/index.astro b/examples/snowpack/astro/pages/index.astro index 48ffa1c89..31dba0f51 100644 --- a/examples/snowpack/astro/pages/index.astro +++ b/examples/snowpack/astro/pages/index.astro @@ -78,7 +78,7 @@ let description = 'Snowpack is a lightning-fast frontend build tool, designed fo
-
+

What is Snowpack?

Snowpack is a lightning-fast frontend build tool, designed diff --git a/src/compiler/optimize/styles.ts b/src/compiler/optimize/styles.ts index 824f53096..563e9b355 100644 --- a/src/compiler/optimize/styles.ts +++ b/src/compiler/optimize/styles.ts @@ -182,7 +182,7 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin }, }, async finalize() { - const allCssModules = new Map(); // note: this may theoretically have conflicts, but when written, it shouldn’t because we’re processing everything per-component (if we change this to run across the whole document at once, revisit this) + const allCssModules: Record = {}; // note: this may theoretically have conflicts, but when written, it shouldn’t because we’re processing everything per-component (if we change this to run across the whole document at once, revisit this) const styleTransforms = await Promise.all(styleTransformPromises); if (!rootNode) { @@ -194,7 +194,7 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin if (styleNodes[n].attributes) { // 1a. Add to global CSS Module class list for step 2 for (const [k, v] of result.cssModules) { - allCssModules.set(k, v); + allCssModules[k] = v; } // 1b. Inject final CSS @@ -231,16 +231,21 @@ export default function ({ filename, fileID }: { filename: string; fileID: strin if (node.attributes[j].name !== 'class') continue; const attr = node.attributes[j]; for (let k = 0; k < attr.value.length; k++) { - if (attr.value[k].type !== 'Text') continue; - const elementClassNames = (attr.value[k].raw as string) - .split(' ') - .map((c) => { - let className = c.trim(); - return allCssModules.get(className) || className; // if className matches exactly, replace; otherwise keep original - }) - .join(' '); - attr.value[k].raw = elementClassNames; - attr.value[k].data = elementClassNames; + if (attr.value[k].type === 'Text') { + // This class is standard HTML (`class="foo"`). Replace only the classes that match + const elementClassNames = (attr.value[k].raw as string) + .split(' ') + .map((c) => { + let className = c.trim(); + return allCssModules[className] || className; // if className matches exactly, replace; otherwise keep original + }) + .join(' '); + attr.value[k].raw = elementClassNames; + attr.value[k].data = elementClassNames; + } else if (attr.value[k].type === 'MustacheTag' && attr.value[k]) { + // This class is an expression, so it’s more difficult (`className={'some' + 'expression'}`). We pass all CSS Module names to the expression, and let it find a match, if any + attr.value[k].content = `(${attr.value[k].content}).split(' ').map((className) => (${JSON.stringify(allCssModules)})[className] || className).join(' ')`; + } } } }