Files
frontend/packages/sass-importer/README.md
2026-09-08 23:23:19 +04:00

4.2 KiB
Raw Blame History

@advdominion/sass-importer

Кастомный импортёр для sass-embedded, который берёт резолв @use/@forward-импортов на себя и читает файлы через node:fs.

Зачем

В проектах на Yarn PnP пакеты лежат не в node_modules, а внутри .zip по виртуальным путям:

.yarn/__virtual__/@example-example-virtual-.../cache/@example-example-....zip/node_modules/@example/example/...

.zip-путь может открыть только код, читающий файлы через node:fs (в нём есть PnP-хуки). А sass-embedded читает файлы своим отдельным кодом, node:fs не использует, поэтому импорты внутри пакетов не резолвятся. Этот импортёр обходит проблему: он сам превращает импорт в существующий файл (canonicalize) и отдаёт его содержимое через readFileSync (load).

Работает и в node-modules-проектах — там require без PnP-хуков, но тот же резолв остаётся корректным.

Установка

yarn add -D @advdominion/sass-importer

Использование

import { createRequire } from 'node:module';
import { createImporter } from '@advdominion/sass-importer';

const require = createRequire(import.meta.url);
const importer = createImporter(require);

const { css } = compiler.compileString(source, {
    importers: [importer],
    loadPaths: ['src/styles'],
});

Импортёр принимает require из createRequire(import.meta.url): в PnP он несёт PnP-хуки, в node-modules — обычный require. Это позволяет резолвить и пакеты, и их внутренние относительные импорты одинаково надёжно.

API

createImporter(require): Importer

  • require — функция резолва (обычно createRequire(import.meta.url)), используется для ветки pkg:.
  • Возвращает объект из двух колбэков для sass-embedded: canonicalize и load.

canonicalize(url, ctx) превращает импорт в канонический file:// URL или возвращает null («я не знаю такой файл» — тогда Sass перебирает следующие импортёры/loadPaths).

load(canonicalUrl) отдаёт содержимое файла и его синтаксис (syntax: 'scss'). Если файла нет — бросает Error: Stylesheet not found: <путь>.

Правила резолва

Приоритет Вариант Пример
1 Точное совпадение @use 'variables'variables (файл)
2 Файл с расширением @use 'variables'variables.scss
3 Каталог с _index @use './lib'./lib/_index.scss
4 Каталог с index @use './lib'./lib/index.scss

Для каталогов берутся _index и index как с .scss, так и с .css. Порядок проверок соответствует порядку перебора Sass, поэтому первая найденная запись — приоритетная.

Виды импортов

  • pkg:@scope/pkg/path/to/filerequire.resolve + резолв кандидата.
  • file:///abs/path → кандидат по файловому пути.
  • относительные (../../variables) → склейка с каталогом содержащего файла (берётся из ctx.containingUrl), затем резолв кандидата.
  • абсолютные (/...) и незнакомые схемы (http:, data:) → отдаёт null, резолв остаётся на Sass.

Лицензия

MIT