Перейти к содержанию

Публичные экспорты и версии библиотеки

Завершим «Набор» структурой пакета. До этого компоненты импортировались внутри мастерской по относительным путям. Теперь определим публичный вход, экспорт CSS и правила совместимости. Цель — отделить поддерживаемый интерфейс библиотеки от внутренних историй и составных демонстраций. Пакет останется локальным и неопубликованным; сборка, упаковка и отправка в реестр не выполняются.

Публичный интерфейс — то, на что потребитель вправе опираться. Если разрешить импортировать любой файл из src, внутренний эксперимент легко станет внешней зависимостью. Потом автор не сможет переименовать историю или убрать демонстрационную форму без риска сломать клиента. Явные exports ограничивают область договора и делают её видимой в package.json. Для «Набора» это четыре компонента и общий stylesheet.

Вход React-компонентов

Файл src/index.ts экспортирует Button, TextField, Dialog и Notice вместе с их типами. ProfileEditor остаётся демонстрацией, а истории вообще не входят в библиотечный вход. Потребитель получает механизмы, но не обязан принять конкретное правило названия организации или таймер сохранения. Такое решение сохраняет границу, которую мы последовательно проводили в предыдущих уроках.

Полный файл src/index.ts для этого состояния:

export { Button, type ButtonProps } from './Button.js';
export { TextField, type TextFieldProps } from './TextField.js';
export { Dialog, type DialogProps } from './Dialog.js';
export { Notice, type NoticeProps } from './Notice.js';

Полный файл package.json для этого состояния:

{
  "name": "@kontur/nabor",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "storybook": "storybook dev -p 6006 --host 127.0.0.1",
    "build-storybook": "storybook build",
    "build": "tsc -p tsconfig.library.json"
  },
  "dependencies": {},
  "devDependencies": {
    "storybook": "10.2.9",
    "@storybook/react-vite": "10.2.9",
    "@storybook/addon-docs": "10.2.9",
    "@storybook/addon-a11y": "10.2.9",
    "vite": "7.1.7",
    "typescript": "5.9.2",
    "@types/react": "19.1.13",
    "@types/react-dom": "19.1.9",
    "react": "19.1.0",
    "react-dom": "19.1.0"
  },
  "peerDependencies": {
    "react": "^19.1.0",
    "react-dom": "^19.1.0"
  },
  "files": [
    "dist",
    "src/styles.css"
  ],
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js"
    },
    "./styles.css": "./src/styles.css"
  },
  "sideEffects": [
    "**/*.css"
  ]
}

Полный файл tsconfig.library.json для этого состояния:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "noEmit": false,
    "declaration": true,
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": [
    "src/index.ts",
    "src/Button.tsx",
    "src/TextField.tsx",
    "src/Dialog.tsx",
    "src/Notice.tsx"
  ],
  "exclude": [
    "src/**/*.stories.tsx"
  ]
}

В import-путях barrel использовано расширение .js, хотя исходные файлы имеют .tsx. При выбранном TypeScript-профиле это описывает пути будущего JavaScript-выхода. Относительные импорты в ESM должны быть понятны среде потребителя. Нельзя просто считать исходный TSX готовым JavaScript-пакетом. Наш профиль предусматривает отдельное преобразование, однако его выполнение ещё не проверено и выходной каталог не прилагается как якобы собранный результат.

tsconfig.library.json задаёт emit JavaScript и деклараций, rootDir и outDir. В include перечислены публичный вход и нужные компоненты. Истории и демонстрации не должны случайно попасть в библиотечную сборку из широкого шаблона. Конфигурация мастерской при этом остаётся отдельно и продолжает видеть stories. Это две разные формы доставки одного проекта: инструмент разработки и пакет для приложения.

Прямые и peer-зависимости

React и React DOM перенесены в peerDependencies публичного профиля и оставлены точными devDependencies учебной среды. Peer-диапазон сообщает, с какой версией клиента рассчитано совместное использование. Библиотека не должна незаметно создавать отдельную копию React для каждого потребителя. При этом выбранный диапазон не является доказательством проверки всех возможных версий внутри него. Нужна независимая матрица совместимости, если команда действительно хочет обещать широкий профиль.

В нашей локальной структуре private: true сохранён. Это защищает от случайного выпуска учебного пакета в реестр. Чтобы перейти к настоящему распространению, потребуется отдельное разрешённое решение, проверка состава артефакта, лицензии, версий и поведения. Удалить флаг недостаточно для готовности продукта. Текущий lesson-12 объясняет архитектуру упаковки, а не заявляет завершённую публикацию.

Список files включает будущий dist и исходный stylesheet. exports даёт отдельный путь ./styles.css. Потребитель должен импортировать CSS явно и установить .nabor-theme вокруг своей области. React-export не выполняет эту настройку автоматически. Выделенный CSS-вход помогает сборщику и человеку понять интеграцию. Свойство sideEffects сохраняет стили как значимое действие, чтобы оптимизация пакета не рассматривала их как заведомо ненужный импорт.

Версия и характер изменения

Пакет обозначен как 0.1.0, то есть ранний локальный профиль. В CHANGELOG записано, что tarball не создавался и выпуск не выполнялся. Дальнейшая версия должна описывать итоговую область изменений. Добавление необязательного варианта без изменения прежних defaults может быть совместимым расширением. Удаление варианта, изменение исходного type или переименование поддерживаемого токена способны нарушить ожидания потребителя и требуют миграционного объяснения.

Смена цвета тоже не всегда чисто внутренняя правка. Если потребитель рассчитывал на определённую пару текста и поверхности или переопределял публичные токены, изменение может затронуть доступность и внешний вид. Поэтому совместимость дизайн-системы включает визуальные и пользовательские договоры наряду с типами. Нельзя обещать отсутствие влияния только потому, что TypeScript-пропсы не изменились. Нужно назвать конкретные наблюдаемые последствия.

Переход потребителя

Миграционная запись должна объяснять прежний и новый способ использования. Если появится pendingLabel, покажите, как настроить подпись ожидания и какие defaults сохраняются. Если разделится опасное действие, приведите пример прежнего variant и нового выбора. Человеку полезнее конкретный переход для его формы, чем общая фраза «улучшен API». Именно поэтому публичный вход и ограничения документации формируются раньше настоящего выпуска.

Не переносите служебную зависимость Storybook в runtime-потребителя только ради одного компонента. Она нужна мастерской, а не странице организации. При проверке будущего пакета отдельно рассматривают зависимостное дерево и содержание артефакта. В нашей работе пакетные команды не запускались, поэтому нельзя заявить фактический размер, отсутствие всех лишних модулей или успешный tree shaking. Эти свойства предстоит подтвердить по настоящему результату сборки.

Что осталось за пределами исходников

Библиотека всё ещё требует независимого подтверждения среды, поведения клавиатуры, цветов, упаковки и интеграции в приложение. Такой перечень соответствует конкретным обещаниям, введённым в курсе. Он не отменяет готовые исходники, а отделяет авторскую подготовку от выпуска. Архив предоставляет двенадцать полных состояний и понятный финальный API, но не содержит node_modules, фиктивного lockfile или исполнявшегося готового dist.

Вы можете продолжить «Набор» отдельным компонентом выбора, таблицей или навигационной ссылкой. Начните с пользовательского договора, затем определите состояния и историю, после этого оформите публичные входы. Не добавляйте элемент только ради роста числа файлов. Сильная библиотека расширяет общий язык интерфейса, сохраняя ясные причины каждого параметра, узнаваемые примеры и честные границы того, что было подготовлено и что ещё требует подтверждения.

Экспорт CSS как часть совместимости

Путь @kontur/nabor/styles.css является поддерживаемым входом, когда пакет будет независимо подготовлен для распространения. Потребитель не должен искать stylesheet по внутренней структуре src вручную. Это помогает менять расположение исходников в будущих версиях, сохранив публичный адрес. Однако содержимое CSS и токены также имеют договор, который надо документировать при изменениях.

До настоящего выпуска сохраните private и статус локального примера. Предстоящая сборка должна подтвердить экспортированные пути, наличие деклараций и отсутствие историй в артефакте. Текущая конфигурация описывает предполагаемую форму результата, но не содержит выдуманного размера или успешного вывода. Подготовка пакета полезна как следующий учебный шаг, пока честно различаются исходная архитектура, фактическое получение артефакта и его дальнейшая публикация.

Оглавление серии, общая подборка и полный архив исходников. Для этого урока выберите lesson-12.

Первичные источники: Storybook CSF, React Vite integration, Аргументы историй, Темы и globals, Декораторы, Accessibility addon, Автоматическая документация, React useId, HTML dialog.

Редакционный статус: локальный черновик. Учебные команды, приложение и проверки не запускались; описанные результаты ожидаемые. Профиль версий закреплён, разрешённый lockfile не создавался.