diff --git a/README.md b/README.md index 96bdc55..02a28e9 100644 --- a/README.md +++ b/README.md @@ -175,6 +175,9 @@ The built-in walker already leans on [`oxc-resolver`](https://github.com/oxc-pro > [!TIP] > Hash-prefixed specifiers defined in `package.json#imports` resolve automatically—no extra loader or `css()` options required. Reach for a custom resolver only when you need behavior beyond what `oxc-resolver` already mirrors. +> [!NOTE] +> Sass-specific prefixes such as `pkg:#button` live outside Node’s resolver and still need a shim. See [docs/sass-import-aliases.md](./docs/sass-import-aliases.md) for a drop-in helper that strips those markers before `@knighted/css` walks the graph. + ```ts import { ResolverFactory } from 'enhanced-resolve' import { css } from '@knighted/css' diff --git a/docs/loader.md b/docs/loader.md index da0762a..ff8b5e6 100644 --- a/docs/loader.md +++ b/docs/loader.md @@ -37,6 +37,9 @@ export default { > [!NOTE] > The loader shares the same auto-configured `oxc-resolver` as the standalone `css()` API, so hash-prefixed specifiers declared under `package.json#imports` (for example, `#ui/button`) resolve without additional options. +> [!TIP] +> Sass-only aliases such as `pkg:#button` never hit Node resolution. Add a small shim resolver (see [docs/sass-import-aliases.md](./sass-import-aliases.md)) when you need to rewrite those specifiers before the loader runs. + ### Combined imports Need the component exports **and** the compiled CSS from a single import? Use `?knighted-css&combined` and narrow the result with `KnightedCssCombinedModule` to keep TypeScript happy: diff --git a/docs/sass-import-aliases.md b/docs/sass-import-aliases.md new file mode 100644 index 0000000..7fc43d4 --- /dev/null +++ b/docs/sass-import-aliases.md @@ -0,0 +1,56 @@ +# Sass import aliases + +Some Sass codebases rely on custom load-path prefixes such as `pkg:#ui/button` or `pkg:@scope/app/components/button`. Those specifiers are resolved by the Sass compiler itself—they never travel through Node.js resolution, `package.json#imports`, or tsconfig `paths`. Because `@knighted/css` reuses Node-style resolution rules underneath (`oxc-resolver`), it cannot interpret Sass-only prefixes automatically. + +The fix is to provide a custom resolver that rewrites those specifiers into absolute paths before the loader (or the standalone `css()` function) tries to walk the dependency graph. + +## When you need a resolver + +Add a resolver whenever you see either of the following: + +- An `@use`/`@import` statement that starts with a nonstandard scheme such as `pkg:` or `sass:`. +- A project-level shorthand that never appears in `package.json#imports` or `tsconfig.json` (for example, `@scope/app` pointing at a workspace directory only Sass knows about). + +Without a resolver, those imports throw “Cannot resolve specifier” errors as soon as `@knighted/css` tries to crawl the module graph. + +## Example: strip `pkg:#` aliases + +```ts +import path from 'node:path' +import { css } from '@knighted/css' + +const pkgAppSrcDir = path.resolve(process.cwd(), 'packages/app/src') + +function resolvePkgAlias(specifier: string): string | undefined { + if (!specifier.startsWith('pkg:')) return undefined + const remainder = specifier + .slice('pkg:'.length) + .replace(/^#/, '') + .replace(/^@scope\/app\/?/, '') + .replace(/^\/+/, '') + return path.resolve(pkgAppSrcDir, remainder) +} + +await css('./src/entry.ts', { + resolver: (specifier, { cwd }) => resolvePkgAlias(specifier) ?? undefined, +}) +``` + +The same helper works inside bundler rules: + +```js +{ + test: /\.[jt]sx?$/, + resourceQuery: /knighted-css/, + use: [ + { + loader: '@knighted/css/loader', + options: { + resolver: specifier => resolvePkgAlias(specifier), + }, + }, + ], +} +``` + +Customize the rewrite logic to match your project’s prefixes or directory layout. Once the resolver returns an absolute file path, `@knighted/css` will process the Sass dependency chain normally and still honor every other built-in resolution feature (tsconfig `paths`, package `imports`, extension aliases, etc.). diff --git a/package-lock.json b/package-lock.json index b2fb417..d8205a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11922,7 +11922,7 @@ }, "packages/css": { "name": "@knighted/css", - "version": "1.0.0-rc.15", + "version": "1.0.0", "license": "MIT", "dependencies": { "es-module-lexer": "^2.0.0", @@ -12222,7 +12222,7 @@ "name": "@knighted/css-playwright-fixture", "version": "0.0.0", "dependencies": { - "@knighted/css": "1.0.0-rc.15", + "@knighted/css": "1.0.0", "@knighted/jsx": "^1.4.1", "lit": "^3.2.1", "react": "^19.0.0", diff --git a/packages/css/package.json b/packages/css/package.json index 69bfc9a..e0e80c0 100644 --- a/packages/css/package.json +++ b/packages/css/package.json @@ -1,6 +1,6 @@ { "name": "@knighted/css", - "version": "1.0.0-rc.15", + "version": "1.0.0", "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.", "type": "module", "main": "./dist/css.js", diff --git a/packages/playwright/package.json b/packages/playwright/package.json index c224150..74c742d 100644 --- a/packages/playwright/package.json +++ b/packages/playwright/package.json @@ -15,7 +15,7 @@ "pretest": "npm run build" }, "dependencies": { - "@knighted/css": "1.0.0-rc.15", + "@knighted/css": "1.0.0", "@knighted/jsx": "^1.4.1", "lit": "^3.2.1", "react": "^19.0.0",