Skip to content

Commit dcfde6e

Browse files
fix: remove source maps from runtime selectors with --hashed. (#71)
1 parent 5612b2e commit dcfde6e

7 files changed

Lines changed: 41 additions & 10 deletions

File tree

docs/type-generation.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ Use `--hashed` when you want `.knighted-css` proxy modules to export `selectors`
6060
CSS Modules hashing instead of stable selector strings. This keeps the module and selector
6161
types while preserving hashed class names at runtime.
6262

63+
> [!NOTE]
64+
> `--hashed` derives the selector list from the compiled CSS, so the generated sidecar can
65+
> include class names that are not exported by the module (for example, sprinkles output from
66+
> vanilla-extract). At runtime, `selectors` reflects only exported locals from the loader bridge, so the runtime map can be a subset of the generated sidecar.
67+
6368
> [!IMPORTANT]
6469
> `--hashed` requires the bundler to route `?knighted-css` imports through
6570
> `@knighted/css/loader-bridge`, so the proxy can read `knightedCss` and

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/css/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,11 @@ selectors.card // hashed CSS Modules class name
137137
> `--hashed` requires wiring `@knighted/css/loader-bridge` to handle `?knighted-css` queries so
138138
> the generated proxies can read `knightedCss` and `knightedCssModules` at build time.
139139
140+
> [!NOTE]
141+
> `--hashed` builds the selector list from compiled CSS. The generated sidecar can therefore
142+
> include class names that are not exported by the module (e.g. sprinkles output), while the
143+
> runtime `selectors` map only includes exported locals from the loader bridge.
144+
140145
Refer to [docs/type-generation.md](../../docs/type-generation.md) for CLI options and workflow tips.
141146

142147
### Combined + runtime selectors

packages/css/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@knighted/css",
3-
"version": "1.1.0",
3+
"version": "1.1.1",
44
"description": "A build-time utility that traverses JavaScript/TypeScript module dependency graphs to extract, compile, and optimize all imported CSS into a single, in-memory string.",
55
"type": "module",
66
"main": "./dist/css.js",

packages/css/src/loaderBridge.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -383,14 +383,18 @@ function resolveCssModules(
383383
if (!locals || typeof locals !== 'object') continue
384384
return locals as Record<string, string>
385385
}
386-
const isStringMapLocal = (value: object): value is Record<string, string> => {
387-
const entries = Object.entries(value)
388-
if (entries.length === 0) return false
389-
return entries.every(([, entry]) => typeof entry === 'string')
386+
const normalizeStringMapLocal = (value: object): Record<string, string> | undefined => {
387+
const entries = Object.entries(value).filter(
388+
([key]) => key !== 'default' && key !== '__esModule',
389+
)
390+
if (entries.length === 0) return undefined
391+
if (!entries.every(([, entry]) => typeof entry === 'string')) return undefined
392+
return Object.fromEntries(entries) as Record<string, string>
390393
}
391394
for (const candidate of candidates) {
392395
if (!candidate || typeof candidate !== 'object') continue
393-
if (isStringMapLocal(candidate)) return candidate
396+
const normalized = normalizeStringMapLocal(candidate)
397+
if (normalized) return normalized
394398
}
395399
const collectNamedExportsLocal = (
396400
value: unknown,
@@ -443,7 +447,7 @@ function createBridgeModule(options: BridgeModuleOptions): string {
443447
`const __knightedResolveCss = ${resolveCssText.toString()};`,
444448
`const __knightedResolveCssModules = ${resolveCssModules.toString()};`,
445449
`const __knightedUpstreamLocals =\n __knightedResolveCssModules(__knightedUpstream, __knightedUpstream);`,
446-
`const __knightedLocalsExport =\n __knightedUpstreamLocals ??\n __knightedResolveCssModules(__knightedLocals, __knightedLocals) ??\n __knightedLocals;`,
450+
`const __knightedLocalsExport =\n __knightedUpstreamLocals ??\n __knightedResolveCssModules(__knightedLocals, __knightedLocals);`,
447451
`const __knightedBaseCss = __knightedResolveCss(__knightedDefault, __knightedUpstream);`,
448452
`const __knightedCss = [__knightedBaseCss, ${cssValues.join(', ')}].filter(Boolean).join('\\n');`,
449453
`export const ${DEFAULT_EXPORT_NAME} = __knightedCss;`,

packages/css/test/loaderBridge.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,23 @@ test('resolveCssModules finds locals on module export', () => {
114114
})
115115
})
116116

117+
test('resolveCssModules ignores default string export', () => {
118+
const module = { default: '.card{color:red}' }
119+
assert.equal(__loaderBridgeInternals.resolveCssModules(module, module), undefined)
120+
})
121+
122+
test('resolveCssModules omits default from named exports', () => {
123+
const module = {
124+
default: '.card{color:red}',
125+
card: 'card_hash',
126+
title: 'title_hash',
127+
}
128+
assert.deepEqual(__loaderBridgeInternals.resolveCssModules(module, module), {
129+
card: 'card_hash',
130+
title: 'title_hash',
131+
})
132+
})
133+
117134
test('pitch returns combined module wrapper when combined flag is present', async () => {
118135
const ctx = createMockContext({
119136
resourceQuery: '?knighted-css&combined',

packages/playwright/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"pretest": "npm run types && npm run build"
3232
},
3333
"dependencies": {
34-
"@knighted/css": "1.1.0",
34+
"@knighted/css": "1.1.1",
3535
"@knighted/jsx": "^1.7.5",
3636
"lit": "^3.2.1",
3737
"react": "^19.0.0",

0 commit comments

Comments
 (0)