Упаковка
Вы можете использовать SvelteKit для создания приложений, а также библиотек компонентов, используя пакет @sveltejs/package (команда npx sv create имеет опцию для настройки этого).
При создании приложения содержимое src/routes является публичной частью; src/lib содержит внутреннюю библиотеку вашего приложения.
Библиотека компонентов имеет точно такую же структуру, как и приложение SvelteKit, за исключением того, что src/lib является публичной частью, и ваш корневой package.json используется для публикации пакета. src/routes может быть сайтом документации или демонстрации, сопровождающим библиотеку, или просто песочницей, которую вы используете во время разработки.
Запуск команды svelte-package из @sveltejs/package возьмет содержимое src/lib и сгенерирует директорию dist (которую можно настроить), содержащую следующее:
- Все файлы в
src/lib. Компоненты Svelte будут предварительно обработаны, файлы TypeScript будут транслированы в JavaScript. - Определения типов (файлы
d.ts), которые генерируются для файлов Svelte, JavaScript и TypeScript. Для этого вам нужно установитьtypescript >= 4.0.0. Определения типов размещаются рядом с их реализацией, рукописные файлыd.tsкопируются как есть. Вы можете отключить генерацию, но мы настоятельно рекомендуем этого не делать — пользователи, использующие вашу библиотеку, могут использовать TypeScript, для которого требуются эти файлы определений типов.
Анатомия package.json
Заголовок раздела «Анатомия package.json»Поскольку вы теперь создаете библиотеку для публичного использования, содержимое вашего package.json станет более важным. Через него вы настраиваете точки входа вашего пакета, какие файлы публикуются в npm, и какие зависимости имеет ваша библиотека. Давайте пройдемся по наиболее важным полям по порядку.
Это имя вашего пакета. Оно будет доступно для других для установки по этому имени и видно на https://npmjs.com/package/<name>.
{ "name": "your-library"}Узнайте больше об этом здесь.
license
Заголовок раздела «license»Каждый пакет должен иметь поле лицензии, чтобы люди знали, как им разрешено его использовать. Очень популярная лицензия, которая также позволяет широкое распространение и повторное использование без предоставления гарантии, — это MIT.
{ "license": "MIT"}Узнайте больше об этом здесь. Обратите внимание, что вы также должны включить файл LICENSE в ваш пакет.
Это сообщает npm, какие файлы он будет упаковывать и загружать в npm. Он должен содержать вашу выходную папку (dist по умолчанию). Ваши package.json, README и LICENSE всегда будут включены, так что вам не нужно их указывать.
{ "files": ["dist"]}Чтобы исключить ненужные файлы (такие как модульные тесты или модули, импортируемые только из src/routes и т. д.), вы можете добавить их в файл .npmignore. Это приведет к пакетам меньших размеров, которые быстрее устанавливаются.
Узнайте больше об этом здесь.
exports
Заголовок раздела «exports»Поле "exports" содержит точки входа пакета. Если вы настроили новый проект библиотеки через npx sv create, оно установлено на единственный экспорт, корень пакета:
{ "exports": { ".": { "types": "./dist/index.d.ts", "svelte": "./dist/index.js" } }}Это сообщает бандлерам и инструментам, что ваш пакет имеет только одну точку входа, корень, и всё должно импортироваться через нее, вот так:
import { Something } from 'your-library';Ключи types и svelte являются условиями экспорта. Они сообщают инструментам, какой файл импортировать при поиске импорта your-library:
- TypeScript видит условие
typesи ищет файл определения типов. Если вы не публикуете определения типов, опустите это условие. - Инструменты, осведомленные о Svelte, видят условие
svelteи знают, что это библиотека компонентов Svelte. Если вы публикуете библиотеку, которая не экспортирует компоненты Svelte и которая может также работать в не-Svelte проектах (например, библиотека хранилищ Svelte), вы можете заменить это условие наdefault.
Вы можете настроить exports по своему вкусу и предоставить больше точек входа. Например, если вместо файла src/lib/index.js, который повторно экспортирует компоненты, вы хотели напрямую предоставить компонент src/lib/Foo.svelte, вы могли бы создать следующую карту экспорта…
{ "exports": { "./Foo.svelte": { "types": "./dist/Foo.svelte.d.ts", "svelte": "./dist/Foo.svelte" } }}…и потребитель вашей библиотеки мог бы импортировать компонент вот так:
import Foo from 'your-library/Foo.svelte';В общем, каждый ключ карты экспорта — это путь, который пользователь должен использовать для импорта чего-то из вашего пакета, а значение — это путь к файлу, который будет импортирован, или карта условий экспорта, которые в свою очередь содержат эти пути к файлам.
Узнайте больше об exports здесь.
Это устаревшее поле, которое позволяло инструментам распознавать библиотеки компонентов Svelte. Оно больше не требуется при использовании условия экспорта svelte export condition, но для обратной совместимости с устаревшими инструментами, которые ещё не знают об условиях экспорта, хорошо сохранить его. Оно должно указывать на вашу корневую точку входа.
{ "svelte": "./dist/index.js"}sideEffects
Заголовок раздела «sideEffects»Поле sideEffects в package.json используется бандлерами для определения, может ли модуль содержать код с побочными эффектами. Модуль считается имеющим побочные эффекты, если он вносит изменения, наблюдаемые из других скриптов вне модуля при его импорте. Например, побочные эффекты включают модификацию глобальных переменных или прототипа встроенных объектов JavaScript. Поскольку побочный эффект потенциально может повлиять на поведение других частей приложения, эти файлы/модули будут включены в финальный бандл независимо от того, используются ли их экспорты в приложении. Лучшей практикой является избегать побочных эффектов в вашем коде.
Установка поля sideEffects в package.json может помочь бандлеру быть более агрессивным в устранении неиспользуемых экспортов из финального бандла, процесс, известный как tree-shaking. Это приводит к меньшим и более эффективным бандлам. Разные бандлеры обрабатывают sideEffects по-разному. Хотя это не обязательно для Vite, мы рекомендуем, чтобы библиотеки указывали, что все CSS-файлы имеют побочные эффекты, чтобы ваша библиотека была совместима с webpack. Это конфигурация, которая поставляется с новыми созданными проектами:
{ "sideEffects": ["**/*.css"]}Если ваш пакет имеет файлы с побочными эффектами, вы можете указать их в массиве:
{ "sideEffects": [ "**/*.css", "./dist/sideEffectfulFile.js" ]}Это будет рассматривать только указанные файлы как имеющие побочные эффекты.
TypeScript
Заголовок раздела «TypeScript»Вы должны поставлять определения типов для вашей библиотеки, даже если вы сами не используете TypeScript, чтобы люди, которые его используют, получали правильную подсказку при использовании вашей библиотеки. @sveltejs/package делает процесс генерации типов в основном непрозрачным для вас. По умолчанию при упаковке библиотеки определения типов автоматически генерируются для файлов Svelte, JavaScript и TypeScript. Всё, что вам нужно обеспечить, — это то, что условие types в карте exports указывает на правильные файлы. При инициализации проекта библиотеки через npx sv create это автоматически настраивается для корневого экспорта.
Если у вас есть что-то кроме корневого экспорта — например, предоставление импорта your-library/foo — вам нужно принять дополнительные меры для предоставления определений типов. К сожалению, TypeScript по умолчанию не будет разрешать условие types для экспорта вроде { "./foo": { "types": "./dist/foo.d.ts", ... }}. Вместо этого он будет искать foo.d.ts относительно корня вашей библиотеки (т. е. your-library/foo.d.ts вместо your-library/dist/foo.d.ts). Чтобы исправить это, у вас есть два варианта:
Первый вариант — требовать, чтобы люди, использующие вашу библиотеку, установили опцию moduleResolution в их tsconfig.json (или jsconfig.json) на bundler (доступно с TypeScript 5, лучший и рекомендуемый вариант в будущем), node16 или nodenext. Это заставит TypeScript учитывать карту экспорта и правильно разрешать типы.
Второй вариант — (зло)употребить функцией typesVersions из TypeScript для подключения типов. Это поле внутри package.json, которое TypeScript использует для проверки разных определений типов в зависимости от версии TypeScript, и также содержит функцию отображения путей. Мы используем эту функцию отображения путей, чтобы получить желаемое. Для упомянутого выше экспорта foo соответствующее определение typesVersions выглядит так:
{ "exports": { "./foo": { "types": "./dist/foo.d.ts", "svelte": "./dist/foo.js" } }, "typesVersions": { ">4.0": { "foo": ["./dist/foo.d.ts"] } }}>4.0 говорит TypeScript проверить внутреннюю карту, если используемая версия TypeScript больше 4 (что на практике всегда должно быть истинным). Внутренняя карта сообщает TypeScript, что типизации для your-library/foo находятся в ./dist/foo.d.ts, что по сути дублирует условие экспорта. У вас также есть * как wildcard в вашем распоряжении, чтобы сделать многие определения типов доступными сразу без повторения. Обратите внимание, что если вы выберете typesVersions, вам придется объявить все импорты типов через него, включая корневой импорт (который определяется как "index.d.ts": [..]).
Вы можете узнать больше об этой функции здесь.
Лучшие практики
Заголовок раздела «Лучшие практики»Вы должны избегать использования специфичных для SvelteKit модулей, таких как $app/environment, в ваших пакетах, за исключением случаев, когда вы планируете, что ваша библиотека будет использоваться только в проектах SvelteKit. Например, вместо использования import { browser } from '$app/environment' вы могли бы использовать import { BROWSER } from 'esm-env' (смотрите документацию esm-env). Вы также можете пожелать передавать вещи вроде текущего URL или действия навигации как проп, вместо прямого полагания на $app/state, $app/navigation и т. д. Написание вашего приложения в более общем стиле также облегчит настройку инструментов для тестирования, демонстраций UI и т. д.
Убедитесь, что вы добавляете алиасы через svelte.config.js (не vite.config.js или tsconfig.json), чтобы они обрабатывались svelte-package.
Вы должны тщательно подумать, являются ли изменения, которые вы вносите в ваш пакет, исправлением ошибки, новой функцией или критическим изменением, и соответствующим образом обновить версию пакета. Обратите внимание, что если вы удаляете какие-либо пути из exports или любые условия экспорта внутри них из вашей существующей библиотеки, это должно считаться критическим изменением.
{ "exports": { ".": { "types": "./dist/index.d.ts",// изменение `svelte` на `default` является критическим изменением: "svelte": "./dist/index.js" "default": "./dist/index.js" },// удаление этого является критическим изменением: "./foo": { "types": "./dist/foo.d.ts", "svelte": "./dist/foo.js", "default": "./dist/foo.js" },// добавление этого нормально: "./bar": { "types": "./dist/bar.d.ts", "svelte": "./dist/bar.js", "default": "./dist/bar.js" } }}Карты исходников
Заголовок раздела «Карты исходников»Вы можете создать так называемые карты объявлений (файлы d.ts.map), установив "declarationMap": true в вашем tsconfig.json. Это позволит редакторам, таким как VS Code, переходить к оригинальному файлу .ts или .svelte при использовании функций вроде Перейти к определению. Это означает, что вам также нужно опубликовать ваши исходные файлы рядом с папкой dist таким образом, чтобы относительный путь внутри файлов объявлений вел к файлу на диске. Предполагая, что весь ваш код библиотеки находится внутри src/lib, как предлагается CLI Svelte, это так же просто, как добавить src/lib в files в вашем package.json:
{ "files": [ "dist", "!dist/**/*.test.*", "!dist/**/*.spec.*", "src/lib", "!src/lib/**/*.test.*", "!src/lib/**/*.spec.*" ]}svelte-package принимает следующие опции:
-w/--watch— наблюдать за файлами вsrc/libи пересобирать пакет при появлении изменений-i/--input— входная директория, которая содержит все файлы пакета. По умолчаниюsrc/lib-o/--output— выходная директория, куда записываются обработанные файлы. Вашpackage.json’sexportsдолжен указывать на файлы внутри нее, и массивfilesдолжен включать эту папку. По умолчаниюdist-p/--preserve-output— предотвратить удаление выходной директории перед упаковкой. По умолчаниюfalse, что означает, что выходная директория будет очищена сначала-t/--types— создавать или нет определения типов (файлыd.ts). Мы настоятельно рекомендуем делать это, так как это способствует качеству экосистемы библиотек. По умолчаниюtrue--tsconfig- путь к tsconfig или jsconfig. Если не предоставлено, ищет следующий верхний tsconfig/jsconfig в пути рабочего пространства.
Публикация
Заголовок раздела «Публикация»Чтобы опубликовать сгенерированный пакет:
npm publishПредупреждения
Заголовок раздела «Предупреждения»Все относительные импорты файлов должны быть полностью указаны, придерживаясь алгоритма ESM Node. Это означает, что для файла вроде src/lib/something/index.js вы должны включить имя файла с расширением:
import { something } from './something/index.js';Если вы используете TypeScript, вам нужно импортировать файлы .ts таким же образом, но используя окончание .js, не .ts. (Это решение TypeScript вне нашего контроля.) Установка "moduleResolution": "NodeNext" в вашем tsconfig.json или jsconfig.json поможет вам с этим.
Все файлы, кроме файлов Svelte (предварительно обработанных) и файлов TypeScript (транслированных в JavaScript), копируются как есть.