[Из песочницы] Angular vs Angular 2: ключевые различия

Мы в команде Web Development компании Itransition уже имеем хороший опыт разработки на Angular 2 и хотим им поделиться.

Эта статья ориентирована на тех крутых ребят, которые разрабатывают на Angular и подумывают перейти на вторую его версию.

Стоит ли начинать новый проект на Angular 2?


Однозначно — да! И вот почему:
  • Это грамотно и тщательно спроектированный, высокопроизводительный фреймворк;
  • С более низким порогом вхождения по сравнению с первой его версией;
  • С хорошей документацией с большим количеством практических примеров.

Начало нового проекта


Наконец-то глоток свежего воздуха, полная свобода, можно начать всё с чистого листа. Хорошенько проработать архитектуру, структуру данных, компоненты, различные абстракции, составить некий словарь терминов приложения и так далее. Чтобы всё было красиво.

Свобода действий


Но с первой версией Angular не всё так просто. Нужно чтобы всё придуманное ложилось на реалии фреймворка, его модули и сервисы строго определенного типа. Нельзя просто так взять и аккуратно создать некий класс или компонент, который будет делать что-то важное. Нужно решить, чем этот компонент будет с точки зрения фреймворка? Каким типом сервиса: «value», «constant» или всё же «factory»? А может быть сервис типа «service»? Ведь он создаёт объект с оператором new, вроде бы это то, что нужно. А вдруг синглтона будет недостаточно? И эти вопросы возникают практически всегда, работая с Angular, в подобных ситуациях, и нет на них однозначного ответа.

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

Генератор кода


Далее для начала работы над проектом необходимо:
  • создать файловую структуру приложения,
  • наладить работу с шаблонами,
  • наладить работу со стилями, препроцессором,
  • настроить сборку для разработки, отладки, продакшена,
  • настроить процесс тестирования,

Со второй версией фреймворка мы получаем инструмент командной строки, с которым можно генерировать приложения, модули, компоненты, директивы, сервисы, фильтры (pipe — новое их название), запускать тесты, проверку кода и т.д. И для выполнения описанного выше необходимо выполнить одну команду:
ng new app-name

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

Команда может принимать дополнительные аргументы. Например, если планируется использовать CSS препроцессор Stylus:

ng new app-name --style=styl

Будет автоматически настроена компиляция и сборка стилей с учётом выбранного препроцессора.

TypeScript


Сгенерированный код приложения будет использовать TypeScript, который пугает многих, скорее всего попросту из-за ошибочных представлений о нём. На самом деле это тот же JavaScript (ECMAScript 6), но с некоторыми приятными и полезными примочками:
  • интерфейсы,
  • типизация,
  • перечисления (Enum),
  • модификаторы (public, private, static),
  • декораторы (@).

Всё это позволяет писать более стабильный и красивый код, избавляет от надобности повсеместно использовать скверный JSDoc.

Начав использовать TypeScript, хочется писать только на нём, и уже не понимаешь, как можно было быть таким грешным — не использовать его раньше?

Компоненты


В Angular 2 нет контроллеров, только компоненты. Создать новый можно таким образом:
ng generate component playground/player

Эта команда создаст директорию player в playground с минимально необходимым кодом компонента:
  1. файл реализации,
  2. файл шаблона,
  3. файл стилей с расширением используемого CSS препроцессора,
  4. файл юнит-тестов.

Никаких копипастов — источника зла и ошибок! Сгенерированный код реализации компонента будет такой:
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-player',
  templateUrl: './player.component.html',
  styleUrls: ['./player.component.styl']
})
export class PlayerComponent implements OnInit {
  constructor() {}

  ngOnInit() {}
}

@ + Component здесь — и есть пример декоратора. В конечном счёте, это простая функция, которая получает в качестве аргумента конструктор, определённый ниже, и изменяет его с учётом описанной конфигурации, в данном случае это:
  1. selector — определяет, как будет называться элемент компонента в шаблонах приложения (),
  2. templateUrl — путь к файлу шаблона текущего компонента,
  3. styleUrls — массив путей к файлам стилей компонента.

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

Two-way binding


Ключевая фишка Angular — two-way binding. Как она реализована в Angular 2?

Такая запись в шаблоне передаст значение свойства playerPosition текущего компонента и будет изменять его при изменении свойства position внутри компонента player. Это и есть two-way binding.

Но почему именно такая довольна странная запись?

В Angular 2 появился новый синтаксис, который позволяет передавать значения свойств дочерним компонентам (one-way binding). Использует он квадратные скобки:


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

Такая запись подразумевает, что в компоненте player есть свойство positionChange, которое является экземпляром класса EventEmitter. И когда в компоненте player вызывается this.positionChange.emit (newValue), выполняется код onPositionChange ($event), указанный в шаблоне. $event будет содержать значение newValue.

Собственно, так в Angular 2 и реализуется two-way binding:

  1. передача исходного значения свойства,
  2. подписка на событие с названием «название свойства внутри дочернего компонента» + «Change»,
  3. изменение свойства в родительском компоненте при появлении события.

А запись [(position)]=«playerPosition» является лишь синтаксическим сахаром, которая делает всё описанное автоматически и экономит время на постройку дома, посадку дерева и выращивание сына.

Благодаря этой реализации в Angular 2 нет вотчеров, которые ранее являлись источников многих проблем с производительностью. Теперь всё более естественно.

Принципы SOLID


В нашей команде мы активно используем принципы SOLID, которые делают поддержку и дальнейшую разработку приложения более эффективным и приятным процессом.

Angular 2 решает множество проблем, связанных с высоким уровнем связанности кода, новой мощной реализацией Dependency Injection и возможностью абстрагироваться от реализаций различных взаимосвязанных компонентов, используя интерфейсы (TypeScript).

Например, можно написать такую конструкцию:

class SomeComponent {
	constructor(public someService: SomeService) {}
}

И при создании экземпляра этого компонента автоматически будет создан экземпляр сервиса SomeService и передан в конструктор SomeComponent. Это очень сильно снижает уровень связанности и позволяет тестировать их в отдельности друг от друга.

Так же, запись public someService (TypeScript) делает этот сервис доступным внутри экземпляра класса с помощью ключевого слова this (this.someService).

Валидация форм


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

Пример реализации формы ввода нового пароля с проверкой его сложности и подтверждением:

let passwordControl = new FormControl('', [
	Validators.required,
	CustomValidators.complexPassword,
]);

let passwordConfirmControl = new FormControl('', [
	Validators.required,
]);

this.formGroup = new FormGroup({
	password: passwordControl,
	passwordConfirm: passwordConfirmControl,
}, CustomValidators.match(passwordControl, passwordConfirmControl));

Валидатор (Validators.required и подобные) — простая функция, в которую передаётся значение и которая возвращает null или объект с описанием ошибки.

В шаблоне формы нужно указать formGroup:


Полям ввода нужно указать соответствующие названия контролов formGroup:


И всё. Валидна ли форма, все ошибки и состояния можно получать через объект formGroup, который будет обновляться при каждом взаимодействии пользователя с ней.

Роутинг


Роутинг похож на прежний, но с некоторыми приятными улучшениями. Например, если какой-нибудь громоздкий модуль приложения используется редко, можно подгружать его динамически:
{
  path: 'profile',
  loadChildren: 'app/profile/prodile.module#ProfileModule'
}

Обработка всех запросов, начинающихся с /profile (/profile/photo, /profile/orders, /profile/orders/: id), будет передана ProfileModule, который будет загружен раз при первой необходимости.

Низкий порог вхождения


В начале статьи говорилось о низком пороге вхождения. Несмотря на всю мощь Angular 2, это действительно так.

На мой взгляд, это из-за того, что:

  • максимально используются возможности JavaScript,
  • многие вещи реализованы более логичным и ожидаемым образом,
  • качество подсказок и авто-завершения на высшем уровне (благодаря TypeScript),
  • имеется командная строка для генерации всего необходимого,
  • хорошая документация.

Но это не говорит о лёгкости его усвоения человеком не знающего JavaScript.

Заключение


Ещё много можно написать про новую версию фреймворка, сравнить основные сервисы, разобраться, как происходит работа с асинхронными операциями (Zone.js), упомянуть о реактивном программировании (Rx.js) и так далее. Но это уже будет не статья, а целая книга.

Хочется сказать, что Angular 2 — очень профессиональный и качественный фреймворк. Работая с ним, чувствуешь, что его писали люди, которые имеют большой опыт практической разработки и понимаешь, что больше не хочется писать на первой его версии.

→ QuickStart

Успехов!

Комментарии (4)

  • 20 января 2017 в 14:23

    0

    Ради любопытства — сколько по времени вы уже используете 2-ю версию и много ли на ней готовых проектов? Какие используете библиотеки / наборы компонентов? Есть ли свои наработки? Если да, есть ли что-то в опенсорсе (или, может быть, планируете).


    Просто сам имею уже год работаю со второй версией, есть своя библиотека (пока внутренняя, но хочется привести её в порядок и сделать публичной) со многими UI компонентами. Интересно, как это всё обстоит в других командах.

  • 20 января 2017 в 14:26

    0

    Вот насчет «низкого порога вхождения» я не соглашусь. Чтобы сделать самое простое приложение на первом Angular, достаточно было скачать angular.js, подключить его в теге script и поехали. Для второй же версии понадобится целый зоопарк технологий и утилит — npm, tsc, typings, system.js, rx.js. Это нормально, потому что более серьезный подход требует больше усилий при старте, но порог вхождения абсолютно точно выше.

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

    • 20 января 2017 в 14:29 (комментарий был изменён)

      0

      Angular CLI сильно упрощает настройку окружения и других рутинных штук до 4–5 команд в консоли. Но да, чтобы начать разрабатывать что-то более-менее серьёзное, нужно немного потрудиться. Порог вхождения действительно не такой уж низкий.

      • 20 января 2017 в 14:39

        0

        По-моему, с ней на тот момент тоже не получилось. Кроме того, у меня было специфическое требование по сборке — все библиотечные файлы в один минифицированный .js, весь пользовательский код — в другой, оба подключить через script и никакой динамической загрузки.

        Так что чтобы утилита начала упрощать жизнь, сначала к ней самой нужно как следует привыкнуть :)

© Habrahabr.ru