[Разработка веб-сайтов, JavaScript, TypeScript] Exports в package.json
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Привет. Я работаю в команде, занимающейся улучшением пользовательского опыта
при работе с деньгами. Front-end мы поставляем npm-пакетами.
В какой-то момент я столкнулся с проблемами, которые привели меня к использованию
поля exports в package.json
Проблема #1
Пакеты могут экспортировать функции с одинаковыми названиями, но делающие разные вещи. Для примера возьмём 2 стейт-менеджера: Reatom и Effector.
Они экспортируют функцию createStore. Если попытаться экспортитировать их из одного пакета (назовём его vendors), то получится следующая картина:
// @some/vendors/index.ts
export { createStore } from '@reatom/core';
export { createStore } from 'effector';
Налицо конфликт имён. Такой код просто не будет работать.
Этого можно избежать за счёт as:
// @some/vendors/index.ts
export { createStore as reatomCreateStore } from '@reatom/core';
export { createStore as effectorCreateStore } from 'effector';
Выглядит, прямо скажем, паршиво. По-хорошему, каждый реэкспорт надо писать через as для поддержания консистентности. Как по мне, это ухудшает DX.
Я начал искать решение, которое позволит избежать и конфликта имён и необходимости писать as. Как бы оно могло выглядеть… Например, вот так:
// @some/vendors/reatom.ts
export { createStore } from 'reatom';
// @some/vendors/effector.ts
export { createStore } from 'effector';
В двух разных файлах мы пишем обычные экспорты и импортируем нужную реализацию createStore:
// someFile.ts
import { createStore } from 'vendors/effector';
Проблема #2
Пакет vendors, скорее всего, содержит не только стейт-менеджер, а ещё какую-то библиотеку. Например, Runtypes.
Если не использовать exports, то импорт будет выглядеть вот так:
// someFile.ts
import { createStore, Dictionary, createEvent, Record } from 'vendors';
Получается какая-то мешанина. На мой взгляд, приятнее было бы читать что-то в стиле:
// someFile.ts
import { createStore, createEvent } from 'vendors/effector';
import { Dictionary, Record } from 'vendors/runtypes';
А ещё хорошо бы скрыть имена библиотек. Это может быть полезно при последующих рефакторингах.
// someFile.ts
import { createStore, createEvent } from 'vendors/state';
import { Dictionary, Record } from 'vendors/contract';
Решение
Чтобы добиться таких импортов, необходимо обратиться к полю exports в package.json
// package.json
"exports": {
"./contract": "./build/contract.js",
"./state": "./build/state.js",
"./package.json": "./package.json"
}
По сути, мы просто говорим сборщику как резолвить импорты. Если вы пишете на TypeScript, то это ещё не всё.
В package.json есть поле types, которое позволяет указать, где находятся типы пакета. В значении у него строка. Не получится указать типы и для contract, и для state. Так что же делать?
Тут на помощь приходит typesVersions в package.json
// package.json
"typesVersions": {
"*": {
"contract": ["build/contract.d.ts"],
"state": ["build/state.d.ts"]
}
}
Мы делаем то же самое, что и в exports, но для d.ts файлов, получая рабочие типы.
Заключение
Использование exports не ограничивается проблемой создания пакета vendors. Его можно использовать для улучшения DX.
Например, в Effector базовый импорт выглядит вот так:
import { createEvent } from 'effector';
А для поддержки старых браузеров вот так:
import { createEvent } from 'effector/compat';
Какие ещё проблемы решает exports можно ознакомиться тут.
Посмотреть на репозиторий с примером здесь.
Спасибо!
===========
Источник:
habr.com
===========
Похожие новости:
- [Ajax, Разработка веб-сайтов, API] Как работать с ошибками бизнес-логики через HTTP
- [Ajax, PHP, JavaScript, CRM-системы] Обзор разработки дополнений для amoCRM, с использованием webHook и виджетов
- [JavaScript, API, Rust, Микросервисы] GraphQL на Rust (перевод)
- [JavaScript, Программирование] Программная генерация изображений с помощью API CSS Painting (перевод)
- [Разработка веб-сайтов, JavaScript, Angular, TypeScript] Как мы делаем базовые компоненты в Taiga UI более гибкими: концепция контроллеров компонента в Angular
- [JavaScript, ReactJS, TypeScript] Структура React REST API приложения + TypeScript + Styled-Components
- [JavaScript, Программирование, Расширения для браузеров, Браузеры] Hello, Word! Разрабатываем браузерное расширение в 2021-м
- [JavaScript, ReactJS] Небольшая практика с JS Proxy для оптимизации перерисовок React компонентов при использовании useContext
- [Высокая производительность, JavaScript, Программирование, WebAssembly] Разгоняем JS-парсер с помощью WebAssembly (часть 1: базовые возможности)
- [Разработка веб-сайтов, Программирование, Анализ и проектирование систем, SQL, Прототипирование] Применяем NOCODE и LOWCODE для вычислений
Теги для поиска: #_razrabotka_vebsajtov (Разработка веб-сайтов), #_javascript, #_typescript, #_package_exports, #_npm, #_javascript, #_typescript, #_frontend, #_package.json, #_exports, #_blog_kompanii_space307 (
Блог компании Space307
), #_razrabotka_vebsajtov (
Разработка веб-сайтов
), #_javascript, #_typescript
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:16
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Привет. Я работаю в команде, занимающейся улучшением пользовательского опыта при работе с деньгами. Front-end мы поставляем npm-пакетами. В какой-то момент я столкнулся с проблемами, которые привели меня к использованию поля exports в package.json Проблема #1 Пакеты могут экспортировать функции с одинаковыми названиями, но делающие разные вещи. Для примера возьмём 2 стейт-менеджера: Reatom и Effector. Они экспортируют функцию createStore. Если попытаться экспортитировать их из одного пакета (назовём его vendors), то получится следующая картина: // @some/vendors/index.ts
export { createStore } from '@reatom/core'; export { createStore } from 'effector'; Налицо конфликт имён. Такой код просто не будет работать. Этого можно избежать за счёт as: // @some/vendors/index.ts
export { createStore as reatomCreateStore } from '@reatom/core'; export { createStore as effectorCreateStore } from 'effector'; Выглядит, прямо скажем, паршиво. По-хорошему, каждый реэкспорт надо писать через as для поддержания консистентности. Как по мне, это ухудшает DX. Я начал искать решение, которое позволит избежать и конфликта имён и необходимости писать as. Как бы оно могло выглядеть… Например, вот так: // @some/vendors/reatom.ts
export { createStore } from 'reatom'; // @some/vendors/effector.ts
export { createStore } from 'effector'; В двух разных файлах мы пишем обычные экспорты и импортируем нужную реализацию createStore: // someFile.ts
import { createStore } from 'vendors/effector'; Проблема #2 Пакет vendors, скорее всего, содержит не только стейт-менеджер, а ещё какую-то библиотеку. Например, Runtypes. Если не использовать exports, то импорт будет выглядеть вот так: // someFile.ts
import { createStore, Dictionary, createEvent, Record } from 'vendors'; Получается какая-то мешанина. На мой взгляд, приятнее было бы читать что-то в стиле: // someFile.ts
import { createStore, createEvent } from 'vendors/effector'; import { Dictionary, Record } from 'vendors/runtypes'; А ещё хорошо бы скрыть имена библиотек. Это может быть полезно при последующих рефакторингах. // someFile.ts
import { createStore, createEvent } from 'vendors/state'; import { Dictionary, Record } from 'vendors/contract'; Решение Чтобы добиться таких импортов, необходимо обратиться к полю exports в package.json // package.json
"exports": { "./contract": "./build/contract.js", "./state": "./build/state.js", "./package.json": "./package.json" } По сути, мы просто говорим сборщику как резолвить импорты. Если вы пишете на TypeScript, то это ещё не всё. В package.json есть поле types, которое позволяет указать, где находятся типы пакета. В значении у него строка. Не получится указать типы и для contract, и для state. Так что же делать? Тут на помощь приходит typesVersions в package.json // package.json
"typesVersions": { "*": { "contract": ["build/contract.d.ts"], "state": ["build/state.d.ts"] } } Мы делаем то же самое, что и в exports, но для d.ts файлов, получая рабочие типы. Заключение Использование exports не ограничивается проблемой создания пакета vendors. Его можно использовать для улучшения DX. Например, в Effector базовый импорт выглядит вот так: import { createEvent } from 'effector';
А для поддержки старых браузеров вот так: import { createEvent } from 'effector/compat';
Какие ещё проблемы решает exports можно ознакомиться тут. Посмотреть на репозиторий с примером здесь. Спасибо! =========== Источник: habr.com =========== Похожие новости:
Блог компании Space307 ), #_razrabotka_vebsajtov ( Разработка веб-сайтов ), #_javascript, #_typescript |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 07:16
Часовой пояс: UTC + 5