Как некоторые из вас, возможно, знают, я был своего рода архитектором игрового движка и в прошлом делал некоторые низкоуровневые кроссплатформенные 2D/3D вещи. Придя из хардкорного уголка Интернета C/C++, я тем временем переключился на ECMAscript6, и я действительно предпочитаю его даже Haskell, CommonLISP и Python. Я также совершенно ленив, поэтому мне нравится, по крайней мере, автоматизировать свою жизнь, насколько это возможно.
Решил написать про Angular2. Моя новая работа требует, чтобы я разрабатывал с Angular2, они не делают ничего, связанного с моими предыдущими исследованиями в области искусственного интеллекта или движка, и они делают в основном только материал 0815 HTML5; так что я как бы новичок во всей этой истории Angular2 Typescript SystemJS. Я не уделял Angular1 особого внимания — после двух проектов, которые я сделал с ним, я вскоре понял, что это концептуальная катастрофа.
Мой друг, также знакомый с типичными концепциями игровых движков и кросс-платформенной (не кросс-браузерной, в этом разница…) разработкой, попросил меня написать кое-что о моем опыте работы с ним.
Это сложно описать, и у меня очень смешанные чувства по поводу Angular, но я стараюсь быть максимально объективным. Пожалуйста, будьте добры, я очень стараюсь. Я также пытаюсь осветить здесь точку зрения UX (с точки зрения новичка), потому что она наиболее актуальна. Невозможная отладка — это убийца для меня, чтобы использовать любой фреймворк.
Учебники по Angular 2
Количество рабочих руководств по Angular 2 очень мало. Если вы думаете, что Angular Class актуален, вы ошибаетесь. Все, что связано с Angular 2, обновляется только на сайте angular.io. Даже если учебнику, который вы найдете, 9 дней, он, вероятно, устарел. В настоящее время в кодовой базе Angular 2 переименовываются и реструктурируются очень многие вещи, и очень важно использовать «@angular/submodule» в качестве имени пакета. Если вы этого не сделаете, все сгорит быстрее, чем вы сможете это исправить.
С точки зрения новичка это не так уж и хорошо. У вас нет работающего Boilerplate, у вас есть только учебник на тысячу страниц и не с чего начать. Поскольку в Angular 2 по-прежнему нет обязательных соглашений по коду или проекту, почти все, что вы найдете на github, сломается, когда вы начнете копировать/вставлять/изменять его в своем проекте.
Рекомендация здесь: используйте репозиторий github для руководства разработчика Angular. Используйте вложенные папки для различных шагов учебника, чтобы люди могли загрузить простой ZIP-файл и распаковать его, выполнить `npm install`, и все заработает прямо из коробки. Если вам нужно начать с самого начала, чтобы понять, как работает внедрение зависимостей, это будет полный кошмар. Ни у кого нет времени на трехчасовой туториал, чтобы разобраться в деталях реализации. С ZIP-файлами у вас нет проблем, много пользы, все в порядке, и каждый может их использовать.
Сообщения об ошибках и отладка
Сообщения об ошибках в Angular 2 настолько общие, что вы понятия не имеете, что происходит. Всегда будет сообщение «не удается найти свойство blub», и оно может быть буквально связано с чем угодно в коде, от компонентов до HTML и даже от повторного использования компонентов и/или служб и директив.
Типичные проблемы, с которыми вы столкнетесь в первые дни, это:
- Невозможно выполнить привязку к routerLink, так как это неизвестное свойство [StackOverflow] [StackOverflow2]
- Вам нужно активировать HashLocationStrategy (второй ответ, не принятый), чтобы предотвратить ошибку 404 перезагрузки браузера на любом подмаршруте. Сервер по умолчанию (рекомендуемый в руководстве по angular.io) не предоставляет работающую конфигурацию.
- RouteParams устарел (независимо от того, что говорит Учебник), и вам нужно использовать ROUTER_PROVIDERS. Если вам интересно, как вы можете получить доступ к текущему активному маршруту, вам нужно использовать [routerLinkActive] и ActivatedRoute, но только для представлений Master/Detail. Если вы хотите иметь, скажем, список элементов и подробное представление, то этот подход не сработает, и вам потребуется итерация + внедрение зависимостей модели (описано позже).
- Внедрение зависимостей использует синтаксис `@Decorator()`. Каждый раз, когда вы делаете что-то вроде `@Component` или `@Input`, вы вводите зависимости. Мне потребовалось много времени, чтобы понять это, потому что Учебник angular.io по внедрению зависимостей не говорит вам об этом.
- Сервисы внедряются с помощью Dependency Injection.
- Убедитесь, что все обозначения тега ‹router-outlet› присутствуют практически во всех шаблонах компонентов, иначе повторное использование компонентов практически невозможно. Посмотрите на этот вопрос о SO, который заставил меня это понять.
Компоненты (ну не очень)
Компоненты Angular2 плохо спроектированы с точки зрения архитектуры. У них всегда есть пути относительно исполняемой среды, а это означает, что рабочий процесс исходного кода / сборки / дистрибутива полностью завершится ошибкой, если у вас есть относительные пути (за исключением того, что вы просто снова скопируете / вставите все в гигантский gulpfile).
Например, любой компонент должен иметь templateUrl и styleUrls, которые относятся к точке входа main.ts. Это означает, что если у вас есть такая структура папок, как «./client/src/app/components/dashboard/dashboard.ts», вам придется использовать «app/components/dashboard/dashboard.html» в качестве пути. Вы не можете просто использовать «./dashboard.html», потому что это было бы слишком просто и имело бы больше смысла, потому что в любом случае это декоратор `@Component`.
Все компоненты в основном нуждаются в ROUTER_DIRECTIVES в них, иначе вам будет очень и очень плохо отлаживать их. Если вы хотите взаимодействовать со своим приложением (например, переходить к другим ссылкам или иметь кнопку «Назад», которая так или иначе есть в каждом компоненте), вам нужен файл ROUTER_DIRECTIVES. Почему это не дефолт - загадка, потому что никто вам этого не говорит. Кроме того, это означает, что компоненты не могут быть разделены, потому что они всегда зависят от настройки маршрутизатора (и, следовательно, директив маршрутизатора со статическими картами, такими как «/dashboard/blub»). Поэтому совершенно бессмысленно иметь специальное свойство [routerLink], если оно не сопоставлено и, следовательно, не выполняет никакой задачи по сравнению с простым ‹a href=”/static/path”›, который заполняет точно такой же набор функций без ошибок отсутствующих свойств и ROUTER_DIRECTIVES, которые необходимо внедрить. Просто говорю'.
С моей личной точки зрения, это все причины, по которым компоненты Angular не являются компонентами. Компоненты работают по принципу «включай и работай», имея идею не распространять связующий код. В Angular 2 это не так, поэтому они не являются ни компонентами, ни сущностями.
StyleUrl каждого компонента (файл CSS) требует глобальных стилей при использовании в качестве подкомпонента. Это означает, что эти стили могут быть написаны только внутри мастера, а не самого подкомпонента.
Например, у вас есть компонент DashboardComponent, отображающий несколько компонентов EventComponents. Если вы думаете, что можете просто написать CSS EventComponent внутри файла CSS EventComponent; тогда вы ошиблись. Окончательная инкапсуляция представления (независимо от того, что вы установили) сгенерирует nghost для элемента Dashboard и ngcontent для элемента Event в DOM. Это означает, что элемент Event не поддерживает стиль в настройке Master/Children.
Система сборки
Система сборки в настоящее время представляет SystemJS. Лично я считаю, что идея, лежащая в основе SystemJS, великолепна, но реализация и API — нет.
- Файлы TypeScript должны быть созданы tsc, компилятором typescript. Для этого вам нужно использовать файл tsconfig.json. Нужно убедиться, что в tsconfig есть запись «module=system» и «moduleResolution=node». В противном случае вам будет трудно его отлаживать, потому что почти невозможно отследить, какие ошибки возникнут.
- Typings по-прежнему глючит и игнорирует подпапки, поэтому, если вы хотите игнорировать typings/foo и typings/bar, он не будет игнорировать все записи (даже node_modules как отдельную запись в конфигурации). Так что в основном просто используйте записи верхнего уровня, иначе это тоже все испортит.
- SystemJS-Builder — рекомендуемый инструмент для объединения всего. Оказывается, комплектация сложнее, чем вы думаете. Angular имеет определенный порядок зависимостей от других библиотек. Точный порядок: «core-js/shim.js», «zone.js», «Reflect.js» и «system.js». После этих полифилов вы можете загрузить «Rx.js» и «angular» и объединить все вместе. Убедитесь, что полифилы разделены, иначе все сгорит в большом аду. Кроме того, в сборщике systemjs нет функций для простого экспорта файла конфигурации systemjs. Это означает, что для каждой сборки вам нужно вручную создать свой собственный файл конфигурации systemjs, в зависимости от того, _ГДЕ_ вы их используете, и вам нужно изменить разрешение модуля в зависимости от среды (времени выполнения). Да, это полностью мешает основной цели существования systemjs. Кроме того, минимизация — это непросто, вам нужно иметь фиктивные пакеты в конфигурации systemjs для каждого пакета, который вы собираете в файл. Например, «@angular/core» должен иметь «{main:’index’}» только для того, чтобы загрузчик знал, что уже было загружено до того, как вы передали ему конфигурацию. Да, это концепция проваливается на многих уровнях.
- Как я уже говорил, компоненты имеют относительные пути к своим файлам CSS. Это означает, что все элементы CSS (при условии, что вы используете :host и другие селекторы веб-компонентов) по-прежнему должны поставляться в несжатом виде или должны быть встроены в файлы JS (опять же, это нехорошо из-за развязки). Я не нашел способа автоматически встроить CSS/HTML без разрушения всей кодовой базы, но я слышал, что это «легко» сделать.
Возможно, поможет gulp-inject, но, как вы уже поняли, этот материал сильно неавтоматизирован и приводит к тому, что файл gulp превышает 900 LOC для одной сборки. Так что я думаю, что вся эта SystemJS/TypeScript/что бы там ни было, это провал дизайна. Отсутствие условностей, отсутствие автоматизации и отсутствие смысла дублирования информации на всех уровнях. Построитель systemjs может автоматизировать почти все, потому что он уже все знает, когда вы создаете его в контексте nodejs. Его просто нужно экспортировать и внедрить. Я не хочу писать файлы сборки половину своей жизни, черт возьми.
Модели и услуги
Я должен сказать, что подход Angular 2 к внедрению моделей и сервисов очень хорош по сравнению с чем-либо еще. Декораторы облегчают каждую инъекцию, и вы можете просто указать ее в конструкторе в качестве параметра, и она будет автоматически внедрена. Конечно, вам нужно использовать синтаксис импорта в коде и вам нужны относительные пути (что делает невозможным их отделение от компонентов).
Но да, это как-то все еще приятно, я думаю. Наверное, мне больше нравятся декораторы, а не то, что с их помощью создано.
Внедрение зависимости
Я думаю, что Внедрение зависимостей в Angular полностью работает с декораторами. Я не совсем уверен, но вот как это выглядит, поскольку каждая зависимость, связанная с фреймворком Angular, внедряется с помощью `@Component`, `@Injectable` и `@Input` (например). Если вы не используете их декораторы, вам будет еще труднее внедрять все вручную.
Пока мне нравятся декораторы, но не то, как их использует Angular. Они могут просто предоставить API, основанный на соглашениях (с их поведением по умолчанию), и предоставить необязательный API настроек для переопределения этих значений по умолчанию.
Например, необходимость внедрить ROUTER_DIRECTIVES, установить templateUrl, установить styleUrls, установить селектор, установить службу, установить модель, установить для нее Injectable — ВСЕ полностью автоматизированы. -способный. Конечно, единственным исключением здесь является `@Input`, но я согласен с этим, потому что он предлагает хороший API для перезаписи входного параметра (открытая панель `@Input('foo') позволяет использовать новый Qux({ foo: contentofbar })).
И под автоматизируемостью я подразумеваю, что информация, необходимая для выполнения задачи, уже есть без нее. Все можно автоматизировать с помощью соглашений. И поэтому я ненавижу это. Я так ненавижу это, потому что подход Angular удаляет идею композитов из декораторов. Какого черта, он удаляет шаблон проектирования, основанный на поведении, потому что все абстрагируется как во времени, так и в местоположении.