Пример организации кода для сложного Angular проекта

    Официальная документация Angular неплохо описывает, а angular-cli автоматически создает структуру относительно простого проекта. Но по мере его развития сложность неизбежно растет и возникает естественная необходимость как-то этой сложностью управлять. В том числе и за счет декомпозиции.



    (Изображение взято из статьи "12 Things to Help Large Organizations Do Angular Right" )


    Данная публикация есть практическое осмысление статей "12 Things to Help Large Organizations Do Angular Right" (Victor Savkin, Co-founder of Narwhal Technologies (nrwl.io) и "Angular: Understanding Modules and Services" (Michele Stieven, Web Developer & JS enthusiast) через призму собственного опыта работы с фреймворком.


    Задача


    Организовать исходный код семейства приложений с общими библиотеками так, чтоб он удовлетворял следующим требованиям:


    • Моно-репозитарий — весь исходный код в одном репозитарии с единственной пакой node_modules на все веб-приложения и библиотеки.
    • Совместимость с angular-cli без дополнительных надстроек и расширений
    • Возможность независимо друг от друга компилировать библиотеки и собирать веб-приложения.

    Пример приложения


    Для примера, создадим рабочий прототип пиложения hero-app с зависимой библиотекой common-lib. Для примера двух компонент достаточно, но на практике их количество может быть любым в разумных пределах.


    Организация кода


    Судя по всему, базовая концепция angular-cli заключается в создании именно рабочего пространства(workspace) для семейства проектов, а не рабочего каталога для одного единственного. Во всяком случае, свойство apps в виде массива в .angular-cli.json на это ненавязчиво намекает. Этой возможностью и воспользуемся.


    Создадим при помощи стандартного ng new рабочий каталог, а затем немного модифицируем его, поместив приложение и библиотеку в отдельную папку в src — собственно, она и будет корневой папкой для всех остальных "строительных блоков" нашего решения.



    Затем модифицируем .angular-cli.json так, чтоб он адекватно воспринимал наши изменения в структуре проекта:



    (Примечание: Изначально казалось, что там все просто, но были(и есть) небольшие сюрпризы с относительными путями и тем, как angular-cli их обрабатывает)


    Код библиотек хотелось держать как можно чище, но, поскольку для нормальной работы angular-cli требует наличия конкретных значений в .angular-cli.json, то все, отчасти ненужные, а где-то и просто общие на всех файлы, — поместим в папку src/_common.


    Импорт библиотек


    Использование общей корневой папки src для всего кода делает технически простой задачу импорта нужных файлов, но код вида:


    import {FooBarComponent} from '../../../../../foo-bar.component';

    не только эстетически выглядит ужасно, но и создает проблемы, если мы решим позднее наши библиотеки опубликовать в виде независимых npm-пакетов.
    Благо, возможность конфигурации tsconfig.json элегантно решает эту проблему.



    Результат



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


    Важный акцент: описан не способ создания "настоящих" библиотек для Angular (это отдельная история вроде вот этой), а приведен лишь способ организации кода для достаточно сложного проекта (для решения этой же проблемы есть и другие более профессиональные инструменты).


    Послесловие


    Чтоб не отвлекаться от основной темы статьи, за скобками остались еще ряд интересных моментов вроде:


    • Подключение сторонних библиотек и стилей и вынос настроек подключения в общий код
    • Использование глобальных стилей для стилизации вложенных компонентов
    • Подключение tslib (TypeScript helpers) для незначительного уменьшения размеров бандла
    • Приемы организации приложения: AppRootModule, "features"-module, структура папок
      модулей (использование index.ts c реэкспортом)
    • Особенности импорта модулей между корневым и дочерними lazy-loaded модулями (использование Module.forRoot)

    Но, в той или иной форме, вы сможете найти примеры их решения в коде проекта на GitHub или в статьях, ссылки на которые даны в по ходу текста.

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

    More
    Ads

    Comments 4

      0

      А как вы решили проблемы одинаковых import'ов?


      ERROR in : XXX ... is part of the declarations of 2 modules.


      У меня две платформы и common.
      Собираю в docker'е по одному — избегаю проблему.
      В dev всё хорошо.


      Также пробрасывал env в common.

        0
        Насколько я понимаю ошибка «ERROR in: XXX… is part of the declarations of 2 modules.» возникает, если некоторый компонент включен в несколько модулей, каждый из которых загружается в корневой. Избежать этого можно включая его всегда только в какой-то один (а для переиспользования в том числе и в секцию exports модуля), соответственно, в любом другом модуле, где нужен этот компонент, подключать соответствующий пакет вместо включения в declarations непосредственно сам компонент.

        Для иллюстрации, я обновил код в репозитарии добавив еще одну библиотеку joke-lib и приложение joke-app.

        Вообще концепция NgModules у Google не получилась простой, на мой взгляд. Когда «прямая видимость» кода не гарантирует работоспособность приложения с этим кодом — с этим как-то неуютно уживаться для тех, кто привык к простоте экосистемы JavaScript. А вся история по декомпозиции кода в ангулар-приложении крутится как раз вокруг разбиения всего приложения на NgModule's. Мне как-то встречалась такая аналогия — концептуально смотреть на NgModules как на аналог «сборок» в .NET или «JAR-пакетов» в Java — тогда их воспринимать становится немного полегче.
        0
        Эх, в angular 6 все перевернулось
        Теперь это отдельная папка /projects
        Пока не понятно с импортом библиотеки в таком случае
          0
          На мой взгляд, в ng6 они «в правильную сторону» начали «переворачиваться». Во всякм случае, оригинальная концепция, когда angular-cli управляет воркспейсом(т.е. группой проектов), а не одним проектом — начинает принимать законченные черты. Конечно, в реализации, есть нюансы, но в целом все становится более логично. В части импорта библиотек, по сравнению с ng5, возможностей просто стало больше. Если раньше они выглядели, как «приемные дети», то сейчас библиотеки ведут себя как «полноправные члены семьи». Подключать их к прокту по прежнемому можно как в виде исходников, так и в скомпилированном виде.

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