Тестируем создание библиотеки компонент для Angular с помощью новой команды для Angular/Cli — library


    Когда проектов становится чуть больше чем один, возникает необходимость как-то переиспользовать не только отдельные модули с кодом, но и сами UI-компоненты. Вариантов решения проблемы много — от традиционного копипаста, до настройки отдельного проекта с тестами, документацией и даже блекджеком.


    Проблема в том, что второй вариант требует значительных усилий по подготовке и каждый такой проект уникальный — со своим инструментарием в котором каждому новому разработчику нужно разбираться заново. В конце июля, команда Angular предложила свое, комплексное, решение этой проблемы добавив в angular/cli новую команду для создания библиотек — library.


    Давайте посмотрим, что из этого получилось.


    Для тестов, взята самая свежая из стабильных версий angular/cli — 6.1.5 (04.09.2018)


    Идеальный мир


    В идеальном мире все должно быть удобно. Так, для библиотеки компонент я бы выделил три важных момента


    • Единообразность проектов и быстрый старт
    • Удобство разработки
    • Удобство распространения

    Итак начем со старта


    Для того что бы создать свою библиотеку нам нужно сделать два шага — создать новый проект и добавить к нему библиотеку. Сначала создадим новый проект:


    npx @angular/cli@latest new mylibapp

    npx

    Я использую npx что бы не устанавливать cli глобально и избегать npm run конструкций. Если у вас npm версии 5.2 или новее — попробуйте. Подробнее почитать можно здесь


    После выполнения команды, мы увидим стандартный (для 6 ангуляра, который отличается от 5ой версии) проект в котором будут созданы два под-проекта — основной mylibapp и mylibapp-e2e. Сам angular проект теперь описывается в angular.json.



    Библиотеки, как видим, пока нет.


    И вот он первый нюанс. Наше название уже занято основным проектом, и назвать библиотеку так же уже не выйдет. Поэтому, если вы хотите назвать библиотеку my-super-library, сначала нужно создать проект, который должен называться как-то по-другому. Например, my-super-library-project. И только потом, создавать библиотеку с желаемым названием.


    Теперь создадим третий под-проект и сгенерируем библиотеку.


    cd mylibapp
    npx ng generate library mylib --prefix mlb

    Указывать префикс не обязательно, но очень желательно что бы не пересекаться с другими библиотеками.



    Как видно, теперь, третьим под-проектом добавилась наша наша библиотечка. Она имеет свой отдельный package.json, tsconfig и karma.conf.js, что позволяет настраивать ее без боязни задеть остальные проекты. Кстати, при желании мы можем добавить еще одну библиотеку и она тоже будет отдельным подпроектом. Но вот почему библиотеку нельзя было выделить совсем отдельным проектом (как например в .Net) я не знаю. И если e2e проект не сложно удалить руками, то основной проект — уже нет. В итоге в репозитории появляется лишний код, что не очень хорошо.


    Теперь давайте посмотрим, какие инструменты мы получаем сразу. Это связка tslint + codelyzer, karma + jasmine и protractor для e2e. Т.е. стандартный набор angular проекта, ничего специфичного для библиотеки нам не подвезли. Это немного странно, так как какой-то инструмент для просмотра компонент и рендера их в документацию (например storybook) просто must have. Но ладно, будем считать, что тут нам просто оставили пространство для маневра.


    Давайте запустим тесты и линтер что бы убедиться, что все работает.


    npm test mylib
    npx ng lint mylib

    У меня все прошло без проблем, но для тестирования был использован Chrome, что тоже странно. Я ничего против него не имею, но на билд серверах его на 90% не будет. Почему не использовали тот же Puppeteer — не понятно.


    Подведем итоги:


    Плюсы


    • Быстрый старт нового проекта
    • Единообразный подход

    Минусы


    • Лишний код в проекте
    • Очевидные вещи нужно допиливать руками

    Пока ничего критичного, продолжаем копать дальше.


    Разработка


    Кое-какие компоненты у нас уже есть "из коробки", давайте на них посмотрим. Поскольку никаких специальных инструментов у нас нет, будем использовать основной проект (вот он оказывается зачем нужен). Для этого нам нужно сбилдить библиотеку, сделать импорт библиотечного модуля и запустить основной проект.


    немного кода
    npx ng build mylib

    import { MylibModule } from "mylib";
    
    ...
    
    @NgModule({
      declarations: [
        AppComponent,
      ],
      imports: [
        BrowserModule, MylibModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })

    npm start

    После того как все выполнится, мы увидим наш компонент из библиотеки. Но снова есть нюанс — watch режим для библиотеки пока не сделали, нужно каждый раз запускать билд библиотеки самостоятельно? Watch появится только в angular/cli 6.2+. И не из коробки, для этого придется добавить новый флаг в tsconfig.json


    tsconfig.json


    "angularCompilerOptions": {
        "enableResourceInlining": true,
    }

    А после этого запускать билд c флагом watch:


    ng build mylib --watch

    Если же вы в силу каких-то причин будете использовать cli младше 6.2, билдить придется самостоятельно, что, прямо скажем, — плохо.


    Теперь давайте добавим новый компонент. Для этого нужно выполнить стандартную команду generate component. Из-за того, что библиотека не наш основной проект, приходится использовать флаг проекта, что тоже немного раздражает (а вот если бы библиотека была самостоятельным решением...).


    npx ng generate component some-nice-image --project mylib

    Теперь под mylib/src создадим папку assets, добавим картинку и снова пересоберем библиотеку что бы увидеть резульат. И тут нас ждет еще один сюрприз — картинки нет. Оказывается, что ресурсы, используемые в библиотеке не попадают в билд автоматически, их нужно копировать самостоятельно (или вот так). И вроде бы не страшно, но все равно как-то не правильно.


    Зато, из-коробки должен работать tree-shaking. Давайте создадим еще один компонент в библиотеке но не будем использовать его в основном проекте. Собираем основной проект в продакш режиме


    npx build --prod

    И видим, что размер бандла не изменился. Tree-Shaking с библиотеками действительно работает!


    Теперь неплохо было бы попробовать поставить какую-то зависимость. Поскольку каждый проект имеет свой собственный package.json нам нужно сначала перейти в папку библиотеки и выполнять команду npm install


    npm i -D @drag13/when-do
    npm i @drag13/round-to

    Я специально поставил их по-разному что бы проверить как потом с этим справится упаковщик. Все ставится без проблем. Пробуем собрать и получаем предупреждение


    Distributing npm packages with 'dependencies' is not recommended. Please consider adding drag13/round-to to 'peerDependencies'or remove it from 'dependencies

    Распространение npm пакетов с зависимостями не желательно. Пожалуйста, подумайте, что бы добавить зависимость drag13/round-to к peerDependencies или вообще убрать ее из зависимостей


    а, затем, и ошибку:


    Dependency drag13/round-to must be explicitly whitelisted

    Зависимость drag13/round-to должна быть явно добавлена в белый список


    Вот это уже интересно, by design, библиотека не хочет иметь прямых зависимостей. Пробуем переместить нашу зависимость в секцию peerDependencies и собраться заново – вуаля, все работает. Но это значит порядок установки сторонних библиотек теперь другой. Сначала ставим зависимость на основной модуль, потом, ручками добавляем в секцию peerDependencies библиотеки.


    Остальное работает так же, как и в обычном Angular проекте.


    Коротко подведем итоги:


    Плюсы:


    • Работаем в знакомом окружении со знакомыми командами
    • Есть tree-shaking из коробки

    Минусы:


    • Для "посмотреть компонент" нужно использовать целый проект
    • Пока еще нет watch режима
    • Ресурсы нужно копировать вручную или настраивать билд-процесс самостоятельно.

    И, наконец, переходим к публикации


    Публикация


    Вот тут все прямо хорошо. Для публикации angular/cli использует уже неплохо зарекомендовавший себя ng-packgr который самостоятельно собирает наш код в пригодный для публикации npm пакет оставляя за бортом настройку package.json файла (а это не мало), минификацию, упаковку в разные форматы (например в UMD).


    Для того, чтобы опубликовать свой пакет (или посмотреть что там внутри) нужно выполнить три команды


    npx ng build --prod
    cd dist/mylib
    npm publish

    Если вы не хотите паблишить, замените команду publish на pack


    В результате у меня получилось следующее:



    Для начала давайте заглянем в package.json, который выглядит совсем не так оригинальный package.json нашей библиотеки.



    Как видим, packagr не стал удалять наши devDependencies, хотя некоторые так делают. Кроме того теоретически радует количество форматов, которые описаны в package.json (пусть я и половины их не знаю).


    Внутри пакет содержит минифицированный и не минифицированный бандл в формате UMD, и еще несколько бандлов внутреннего формата angular (fesm5, fesm2015). Но, главное, теперь об этом не будет болеть голова разработчиков что просто замечательно.


    Перейдем к выводам


    Плюсы:


    • Удобство
    • Продуманность

    Итого


    Решение получилось интересное, но сырое. Старт и публикация очень удобны, но к разработке пока есть вопросы. Особенно растраивает, что сейчас библиотека не является самостоятельным проектом by design, а скорее дополнением к основному проекту с возможностью публикации.


    С другой стороны, проделан большой кусок работы, функционал постоянно развивается, и я уверен, что со временем, мы получим отличный инструмент для разработки.

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 2

      0

      а что-нибудь подобное для vuejs есть?

        0
        Не видел, не подскажу.

      Only users with full accounts can post comments. Log in, please.