Когда я создал angular-async-local-storage, было легко создать модуль Angular и использовать его прямо в моем приложении. Но поскольку он может помочь другим разработчикам, я хотел, чтобы он был модулем многократного использования, упакованным и потребляемым, как любые другие модули Angular.
Я боролся с этой частью здания. Я почти не нашел документации по этому поводу, поэтому попытался скопировать, как работает официальный модуль Http. Теперь все готово, я делюсь своим опытом о создании и публикации модуля Angular.
Этот пост предназначен для опытных разработчиков, которые уже знают основные концепции Angular и знают, как создать базовое приложение. Французская версия этого поста доступна здесь.
Обновление: Angular 6
Это сообщение больше не актуально. В Angular 6 создать библиотеку Angular так же просто, как ng g library name
. См. Официальную документацию по интерфейсу командной строки.
Того же автора
- Расширение Angular schematics для Visual Studio Code: графический интерфейс для команд Angular CLI
- @ Ngx-pwa / local-storage: угловая библиотека для локального хранилища
- Typescript-strict-typed: строгий конфиг для TypeScript и ESLint / TSLint
- Другие популярные Angular посты на Medium
- Подпишись на меня в Твиттере"
- Угловые тренинги на месте (базируются в Париже, поэтому веб-сайт на французском языке, но моя английская биография здесь, и я открыт для путешествий)
Создание модуля Angular: подводные камни
Эта часть полностью аналогична созданию модуля в вашем приложении: импортируйте необходимые модули, объявляйте компоненты, директивы или каналы или предоставляйте некоторые услуги. Следует помнить лишь о нескольких моментах.
Во-первых, никогда не импортируйте BrowserModule. Ваш модуль является модулем feature, только конечный пользователь должен импортировать BrowserModule в модуль root приложения. Если вам нужны общие директивы (* ngIf, * ngFor…), импортируйте CommonModule.
Если ваш модуль предназначен для создания новых компонентов, директив или каналов, не забудьте экспортировать их. Заявленные доступны только внутри вашего модуля.
Самое главное, не смешивать компоненты / директивы / каналы и службы в одном модуле. Почему?
- Служба, предоставляемая в модуле, будет доступна везде в приложении, поэтому ваш модуль следует импортировать только один раз, в модуль root пользовательского приложения (например, модуль Http).
- Экспортированный компонент / директива / канал будет доступен только в модуле, импортирующем ваш, поэтому ваш модуль должен быть импортирован в каждый пользовательский модуль (корневой и / или функциональные модули), которым они нужны (например, CommonModule) .
Если вам это непонятно, вам следует мой другой пост« Понимание модулей Angular (NgModule) и их области действия », поскольку это важный (и сбивающий с толку) момент в Angular.
Наконец, соблюдайте правило Angular: никогда не используйте напрямую API-интерфейсы браузера (например, DOM). Если вы это сделаете, ваш модуль не будет совместим с Универсальным серверным рендерингом и другими расширенными опциями Angular. Если вам действительно нужно использовать API для конкретного браузера (localStorage
…), вам следует попробовать / отловить ошибки.
Экспорт общедоступного API
Когда вы используете официальный модуль Angular, у вас есть только одна точка входа для импорта всего, что вам нужно (например, '@angular/http'
).
Поэтому вам нужно создать index.ts
файл, экспортирующий все общедоступные API вашего модуля. Он должен, по крайней мере, содержать ваш NgModule
, а также ваши компоненты или службы (пользователю нужно будет импортировать их, чтобы внедрить туда, где они необходимы).
Компоненты / директивы / каналы не будут импортированы пользователем напрямую, но вам необходимо экспортировать их, чтобы они были совместимы с AoT (спасибо Isaac Mann за эту информацию).
Инструменты сборки
Вот где я начал бороться. Итак, мне удалось скопировать, как работают официальные модули Angular, такие как HttpModule. Они используют:
- Typescript через компилятор Angular (ngc) для транспилирования,
- Rollupjs для упаковки,
- Uglify-js для минимизации.
npm install
@angular/compiler @angular/compiler-clitypescript rollup uglify-js
--save-dev
Конфигурация TypeScript
Вот tsconfig.json
моего модуля:
Есть несколько важных отличий от вашего классического tsconfig.json
:
- явные
"paths"
для других используемых вами модулей необходимы, так как окончательный комплект не будет включать их напрямую (подробнее об этом позже). "angularCompilerOptions": { "strictMetadataEmit": true }
необходимо для совместимости с AoT."declaration": true
важен для создания файлов определений типов, поэтому у пользователя будет Intellisense для вашего модуля."noImplicitAny": true
и"strictNullChecks": true
рекомендуются во избежание ошибок и для совместимости со всеми пользовательскими конфигурациями."noImplicitAny": true
необходимо соблюдать начиная с Angular 4.0, а"strictNullChecks": true
начиная с Angular 4.1."module": "es2015"
важен для производительности, а"sourceMap": true
- для отладки, но здесь ничего конкретного."stripInternal": true
избегайте бесполезных объявлений для внутренних API и"skipLibCheck": true
избегайте блокирования (безвредными) ошибками в используемых вами библиотеках.
Конфигурация накопительного пакета
Модули Angular поставляются в формате UMD, поэтому ваш rollup.config.js
должен быть установлен соответственно. Вот пример:
Скрипт входа - это ваш перенесенный index.ts
, поэтому он должен соответствовать вашей конфигурации TypeScript. bundles/modulename.umd.js
- это обычный путь и имя, используемое модулями Angular.
Rollup требует moduleName для формата UMD. Это будет объект JavaScript, поэтому не используйте специальные символы (без тире).
Затем именно здесь происходит важный момент. В вашем модуле используются элементы Angular (по крайней мере, NgModule
декоратор), но ваш пакет не должен не включать Angular.
Почему? Angular уже будет включен в приложение пользователя. Если ваш модуль тоже включает его, он будет там дважды, и будут фатальные (и непонятные) ошибки.
Поэтому вам нужно установить Angular как глобальный. И вам нужно знать имя модуля UMD для каждого модуля. Он следует этому соглашению: ng.modulename (ng.core, ng.common, ng.http...)
.
То же самое и с RxJS, если ваш модуль его использует. И имена модулей здесь довольно запутаны. Для классов (Observable
…) это Rx
. Для операторов (map, filter
…) это Rx.Observable.prototype
. Для прямых методов классов (of, fromEvent
…) это Rx.Observable
.
Строительство, наконец
Теперь вы можете собрать свой комплект модулей. Вы можете сохранить командные строки в сценариях npm:
Потом:
npm run build
Обратите внимание, что транспиляция не выполняется непосредственно TypeScript, вам следует использовать компилятор Angular (ngc): это TypeScript с некоторой дополнительной магией Angular.
Публикация в npm
Не публиковать все на npm, только dist
каталог.
Вам нужно будет создать новый конкретный dist/package.json
. Например :
Некоторые конкретные моменты:
"version"
должен следовать семантическому управлению версиями. Любое критическое изменение означает увеличение основного числа (даже если это небольшое изменение). И когда вы изменяете свой модуль, чтобы не отставать от Angular, это незначительное приращение числа."main"
и"module"
пути необходимы для импорта пользователем ."typings"
путь для Intellisense."licence": "MIT"
: важна лицензия на открытый исходный код, иначе ваш модуль бесполезен. Angular использует лицензию MIT, и вам следует ее придерживаться.- Модули Angular, которые вы использовали, будут перечислены в
peerDependencies
. По-прежнему используйте semver со знаком^
, иначе ваш модуль будет устаревать при каждом обновлении Angular. Для других библиотек (RxJS, zone.js…) вы можете увидеть текущие требования Angular здесь.
Не забудьте написать README с документацией по вашему API. В противном случае ваш модуль бесполезен. Вы можете использовать такую библиотеку, как copyfiles, чтобы скопировать README из корневого каталога проекта (отображается на Github) в каталог dist
(отображается в репозитории npm).
А с настроенной учетной записью npm теперь вы можете опубликовать свой модуль:
cd dist npm publish
И в любое время, когда вам нужно обновить свой модуль, просто перестройте его, измените номер версии, обновите журнал изменений и снова опубликуйте.