Skip to content

Commit 5a8afef

Browse files
test: sass node package imports.
1 parent 6080bf5 commit 5a8afef

7 files changed

Lines changed: 84 additions & 13 deletions

File tree

packages/css/src/css.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,8 @@ async function compileSass(
328328
peerResolver,
329329
)
330330
const sass = resolveSassNamespace(sassModule)
331-
const importer = createSassImporter({ cwd, resolver })
332-
const legacyImporter = createLegacySassImporter({ cwd, resolver })
331+
const importer = createSassImporter({ cwd, resolver, entryPath: filePath })
332+
const legacyImporter = createLegacySassImporter({ cwd, resolver, entryPath: filePath })
333333
const loadPaths = buildSassLoadPaths(filePath)
334334

335335
if (typeof (sass as { compileAsync?: Function }).compileAsync === 'function') {

packages/css/src/sassInternals.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import path from 'node:path'
22
import { existsSync, promises as fs } from 'node:fs'
33
import { fileURLToPath, pathToFileURL } from 'node:url'
4+
import { createRequire } from 'node:module'
45

56
import type { CssResolver } from './types.js'
67
import { createResolverFactory, resolveWithFactory } from './moduleResolution.js'
@@ -10,9 +11,11 @@ export type { CssResolver } from './types.js'
1011
export function createSassImporter({
1112
cwd,
1213
resolver,
14+
entryPath,
1315
}: {
1416
cwd: string
1517
resolver?: CssResolver
18+
entryPath?: string
1619
}) {
1720
const debug = process.env.KNIGHTED_CSS_DEBUG_SASS === '1'
1821
const pkgResolver = createPkgResolver(cwd)
@@ -27,7 +30,7 @@ export function createSassImporter({
2730
}
2831
const containingPath = context?.containingUrl
2932
? fileURLToPath(context.containingUrl)
30-
: undefined
33+
: entryPath
3134
if (resolver && shouldNormalizeSpecifier(url)) {
3235
const resolvedPath = await resolveAliasSpecifier(
3336
url,
@@ -88,9 +91,11 @@ export function createSassImporter({
8891
export function createLegacySassImporter({
8992
cwd,
9093
resolver,
94+
entryPath,
9195
}: {
9296
cwd: string
9397
resolver?: CssResolver
98+
entryPath?: string
9499
}) {
95100
const debug = process.env.KNIGHTED_CSS_DEBUG_SASS === '1'
96101
const pkgResolver = createPkgResolver(cwd)
@@ -100,7 +105,7 @@ export function createLegacySassImporter({
100105
prev: string,
101106
done?: (result: { file: string } | null) => void,
102107
) => {
103-
const containingPath = prev && prev !== 'stdin' ? prev : undefined
108+
const containingPath = prev && prev !== 'stdin' ? prev : entryPath
104109
let resolvedPath: string | undefined
105110

106111
if (resolver && shouldNormalizeSpecifier(url)) {
@@ -209,10 +214,22 @@ export function createPkgResolver(cwd: string) {
209214
return async (specifier: string, containingPath?: string) => {
210215
const importer = containingPath ?? path.join(cwd, 'index.scss')
211216
const resolved = resolveWithFactory(factory, specifier, importer, SASS_EXTENSIONS)
212-
if (!resolved) {
217+
if (resolved) {
218+
return ensureSassPath(resolved) ?? resolved
219+
}
220+
const resolvedViaNode = resolveWithNode(specifier, importer)
221+
if (!resolvedViaNode) {
213222
return undefined
214223
}
215-
return ensureSassPath(resolved) ?? resolved
224+
return ensureSassPath(resolvedViaNode) ?? resolvedViaNode
225+
}
226+
}
227+
228+
function resolveWithNode(specifier: string, importerPath: string): string | undefined {
229+
try {
230+
return createRequire(importerPath).resolve(specifier)
231+
} catch {
232+
return undefined
216233
}
217234
}
218235

packages/css/test/generateTypes.test.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import assert from 'node:assert/strict'
22
import fs from 'node:fs/promises'
3+
import { createRequire } from 'node:module'
34
import os from 'node:os'
45
import path from 'node:path'
56
import test from 'node:test'
@@ -362,13 +363,28 @@ test('generateTypes resolves hash-imports workspace package.json imports', async
362363
try {
363364
const appRoot = path.join(workspace.root, 'apps', 'hash-import-demo')
364365
const bridgeDir = path.join(appRoot, 'src', 'workspace-bridge')
366+
const requireFromRepo = createRequire(import.meta.url)
367+
const sassEntry = requireFromRepo.resolve('sass')
368+
const sassPackageDir = await findPackageRoot(sassEntry)
369+
const sassModuleDir = path.join(appRoot, 'node_modules', 'sass')
370+
await fs.mkdir(path.dirname(sassModuleDir), { recursive: true })
371+
try {
372+
await fs.symlink(sassPackageDir, sassModuleDir)
373+
} catch {
374+
await fs.cp(sassPackageDir, sassModuleDir, { recursive: true })
375+
}
376+
await fs.writeFile(
377+
path.join(bridgeDir, 'tokens.scss'),
378+
'$accent-color: dodgerblue;\n',
379+
)
365380
await fs.writeFile(
366-
path.join(bridgeDir, 'workspace-card.css'),
367-
'.knighted-demo { color: dodgerblue; }\n',
381+
path.join(bridgeDir, 'workspace-card.scss'),
382+
"@use 'pkg:#workspace/ui/tokens.scss' as tokens;\n\n" +
383+
'.knighted-demo { color: tokens.$accent-color; }\n',
368384
)
369385
await fs.writeFile(
370386
path.join(appRoot, 'src', 'types-entry.ts'),
371-
"import selectors from '#workspace/ui/workspace-card.css.knighted-css'\n" +
387+
"import selectors from '#workspace/ui/workspace-card.scss.knighted-css'\n" +
372388
'console.log(selectors.demo)\n',
373389
)
374390

@@ -378,16 +394,42 @@ test('generateTypes resolves hash-imports workspace package.json imports', async
378394
include: ['src'],
379395
outDir,
380396
})
381-
assert.ok(result.selectorModulesWritten >= 1)
382-
assert.equal(result.warnings.length, 0)
397+
const unexpectedWarnings = result.warnings.filter(
398+
warning =>
399+
warning.includes('Unable to resolve') ||
400+
warning.includes('Failed to extract CSS'),
401+
)
402+
assert.equal(
403+
unexpectedWarnings.length,
404+
0,
405+
`Unexpected warnings:\n${unexpectedWarnings.join('\n')}`,
406+
)
383407

384-
const selectorModulePath = path.join(bridgeDir, 'workspace-card.css.knighted-css.ts')
408+
const selectorModulePath = path.join(bridgeDir, 'workspace-card.scss.knighted-css.ts')
385409
assert.equal(await pathExists(selectorModulePath), true)
386410
} finally {
387411
await workspace.cleanup()
388412
}
389413
})
390414

415+
async function findPackageRoot(entryPath: string): Promise<string> {
416+
let current = path.dirname(entryPath)
417+
const { root } = path.parse(current)
418+
while (true) {
419+
const candidate = path.join(current, 'package.json')
420+
try {
421+
await fs.access(candidate)
422+
return current
423+
} catch {
424+
// continue
425+
}
426+
if (current === root) {
427+
throw new Error(`Unable to locate package.json for ${entryPath}`)
428+
}
429+
current = path.dirname(current)
430+
}
431+
}
432+
391433
test('generateTypes removes stale selector manifest entries when modules vanish', async () => {
392434
const project = await setupFixtureProject()
393435
try {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"/Users/morgan/knighted/css/packages/playwright/src/hash-imports-workspace/apps/hash-import-demo/src/workspace-bridge/hash-imports.scss": {
3+
"file": "/Users/morgan/knighted/css/packages/playwright/src/hash-imports-workspace/apps/hash-import-demo/src/workspace-bridge/hash-imports.scss.knighted-css.ts",
4+
"hash": "2cb05b82a4776b703d53194253d1659decddd9c7"
5+
}
6+
}

packages/playwright/src/hash-imports-workspace/apps/hash-import-demo/src/render-hash-imports-demo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { HASH_IMPORTS_SECTION_ID } from '../../../constants.js'
22
import { createWorkspaceCard } from '#workspace/ui/workspace-card.js'
33
import { knightedCss as workspaceCardCss } from '#workspace/ui/workspace-card.js?knighted-css'
4-
import stableSelectors from '#workspace/ui/hash-imports.css.knighted-css.js'
4+
import stableSelectors from '#workspace/ui/hash-imports.scss.knighted-css.js'
55

66
export function renderHashImportsWorkspaceDemo(root: HTMLElement): void {
77
const mount = root ?? document.body
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@use 'pkg:#workspace/ui/tokens.scss' as tokens;
2+
3+
.knighted-demo {
4+
color: tokens.$accent-color;
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
$accent-color: #1e40af;

0 commit comments

Comments
 (0)