[Перевод] Быстрый старт за 5 минут с Angular 2

Вашему вниманию предлагается перевод туториала »5 min quickstart» от команды Angular. Туториал описывает процесс создания «Hello World»-приложения на новом фреймворке Angular 2, который недавно получил статус «бета».

45355d3506304ff7a9475e213de4f526.pngДавайте начнём с нуля и построим суперпростое приложение Angular2 на TypeScript.

Демо


Запуск работающего примера — это самый лучший способ увидеть, как оживает приложение на Angular 2.
Нажатие этой ссылки открывает новую вкладку, загружает пример в plunker и отображает простое сообщение:

My First Angular 2 App


Вот файловая структура:

angular2-quickstart
├── app
│   ├── app.component.ts
│   └── boot.ts
├── index.html
└── license.md


Функционально это index.html и два файла TypeScript в папке app/. Давайте сделаем это!

Конечно, мы не будем создавать приложения, которые будут запускаться только в plunker. Давайте сделаем всё как если бы мы делали это в реальной жизни:

  1. Обустроим нашу среду разработки.
  2. Напишем корневой компонент Angular для нашего приложения.
  3. Загрузим его для того, чтобы он принял контроль над главной веб-страницей.
  4. Напишем главную страницу (index.html).


Мы действительно можем собрать QuickStart за пять минут, если будем следовать инструкциям и проигнорируем все комментарии.
Но многие из нас заинтересуются, «почему» и «как» всё это происходит, и ответ на эти вопросы займёт значительно больше времени.


Среда разработки


Нам необходимо место (папка проекта), несколько библиотек, некоторое количество настроек TypeScript и редактор с поддержкой TypeScript на ваш выбор.Создадим новую папку нашего проекта

mkdir angular2-quickstart
cd    angular2-quickstart

Добавим нужные нам библиотеки
Мы рекомендуем использовать менеджер пакетов npm для загрузки и управления библиотеками.

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


Добавьте файл package.json в папку проекта и скопируйте в него следующий код:

// package.json
{
    "name": "angular2-quickstart",
    "version": "1.0.0",
    "scripts": {
        "tsc": "tsc",
        "tsc:w": "tsc -w",
        "lite": "lite-server",
        "start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
    },
    "license": "ISC",
    "dependencies": {
        "angular2": "2.0.0-beta.0",
        "systemjs": "0.19.6",
        "es6-promise": "^3.0.2",
        "es6-shim": "^0.33.3",
        "reflect-metadata": "0.1.2",
        "rxjs": "5.0.0-beta.0",
        "zone.js": "0.5.10"
    },
        "devDependencies": {
        "concurrently": "^1.0.0",
        "lite-server": "^1.3.1",
        "typescript": "^1.7.3"
    }
}


Не терпится узнать детали? Мы изложили их в приложении ниже.


Установите пакеты. Откройте окно терминала (командную строку в Windows) и запустите эту команду npm:

npm install


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


Сконфигурируем TypeScript
Нам необходимо довольно специфично настроить компилятор TypeScript.
Добавьте файл tsconfig.json в папку проекта и скопируйте в него следующее:

// tsconfig.json
{
    "compilerOptions": {
        "target": "ES5",
        "module": "system",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
    },
    "exclude": [
        "node_modules"
    ]
}


Мы исследуем tsconfig.json в приложении ниже.


Итак, всё готово. Давайте напишем немного кода.

Наш первый компонент Angular


Компонент (Component) — это наиболее фундаментальная концепция Angular. Компонент настраивает отображение (view) — часть веб-страницы, где мы показываем информацию пользователю и реагируем на его действия.

Технически, компонент — это класс, который контролирует шаблон отображения. Мы будем писать много таких классов при создании приложений Angular. Это наша первая попытка, так что мы сделаем всё предельно просто.

Создадим подпапку, в которой будут находиться исходники
Мы предпочитаем хранить код нашего приложения в подпапке под названием app/. Выполните следующую команду в консоли:

mkdir app
cd    app


Добавим файл компонента
Теперь добавьте файл с именем app.component.ts и скопируйте в него следующий код:

// app/app.component.ts
import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '

My First Angular 2 App

' }) export class AppComponent { }


Давайте подробно рассмотрим этот файл, начиная с самого конца, где мы определяем класс.Класс Компонента
В самом низу файла располагается пустой и ничем не занятый класс под названием AppComponent. Когда мы будем готовы создать независимое приложение, мы сможем дополнить этот класс свойствами и логикой приложения. Наш класс AppComponent пуст, потому что нам не нужно, чтобы он что-то делал в этом QuickStart.Модули
Приложения на Angular модульны. Они включают в себя множество файлов, каждый из которых имеет определённую цель.

Большинство файлов приложения экспортируют что-нибудь вроде компонента. Наш файл app.component экспортирует класс AppComponent.

// app/app.component.ts (export)
export class AppComponent { }


Факт экспорта превращает обыкновенный файл в модуль. Имя файла (без его расширения), как правило, является именем модуля. Таким образом, 'app.component' — это имя нашего первого модуля.

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

QuickStart не сложен: один компонент — это всё, что нам нужно. Однако модули играют фундаментальную организационную роль даже в таком маленьком приложении.

Модули полагаются на другие модули. В приложениях Angular, написанных на TypeScript, когда нам нужно что-то, предоставляемое иным модулем, мы импортируем его. Когда другому модулю требуется сослаться на AppComponent, он импортирует символ AppComponent следующим образом:

// app/boot.ts
import {AppComponent} from './app.component'


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

Если нам требуется что-то из Angular, мы импортируем это из его библиотечного модуля. И прямо сейчас нам нужно кое-что, чтобы иметь возможность определить метаданные для нашего компонента.

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

Мы определяем метаданные компонента с помощью функции Component из Angular. Мы получаем доступ к этой функции, импортируя её из основной библиотеки Angular — angular2/core.

// app/app.component.ts (import)
import {Component} from 'angular2/core';


В TypeScirpt мы можем связать функцию и класс через превращение функции в декоратор. Для этого перед её названием нужно добавить символ @, и поместить её прямо перед объявлением класса.

// app/app.component.ts (metadata)
@Component({
    selector: 'my-app',
    template: '

My First Angular 2 App

' })


@Component сообщает Angular, что данный класс является компонентом Angular. Объект конфигурации, отправляемый в @Component, имеет два поля: selector и template.

Свойство selector определяет обычный CSS селектор для HTML-элемента my-app, выступающего в качестве хоста. Angular создаёт и отображает экземпляр нашего AppComponent каждый раз, когда он сталкивается с my-app в родительском HTML.

Запомните селектор my-app! Нам будет нужна эта информация, когда мы будем писать наш index.html.


Свойство template содержит шаблон компонента. Шаблон — это разновидность HTML, которая объясняет Angular, как рендерить отображение. Наш шаблон — это единственная строка HTML, объявляющая: «My First Angular App».

Теперь нам нужно как-то объяснить Angular, что этот компонент необходимо загрузить.

Запустим его
Добавьте новый файл, boot.ts, в папку app/, и скопируйте в него следующий код:

// app/boot.ts
import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'

bootstrap(AppComponent);


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

  1. Браузерная функция Angular bootstrap.
  2. Корневой компонент приложения, который мы только что написали.


Мы импортируем и то, и другое. Потом мы вызываем bootstrap и передаём в неё тип корневого компонента AppComponent.

Изучить, почему мы импортируем bootstrap из angular2/platform/browser и почему мы создаём отдельный файл boot.ts, можно в приложении ниже.


Мы попросили Angular запустить приложение в браузере с нашим компонентом в качестве корневого. Однако, где же Angular его запустит?

Добавим страницу index.html


Angular отображает наше приложение в специфическом месте на нашей странице index.html. Пришло время создать этот файл.

Мы не будем класть index.html в папку app/. Мы расположим его на один уровень выше, в корневой папке проекта.

cd ..


Теперь создайте файл index.html и скопируйте в него следующее:




  
    Angular 2 QuickStart

    
    
    
    
    

    
    

  

  
  
    Loading...
  















Здесь есть 3 секции HTML, которые необходимо отметить:

  1. Мы загружаем библиотеки JavaScript, которые нам требуются. angular2-polyfills.js и Rx.js требуются для работы Angular 2.
  2. Мы настраиваем нечто, что называется System, и просим его импортировать файл boot, который мы только что написали.
  3. Мы добавляем тэг в . Это то самое место, где обитает наше приложение!


Что-то должно найти и загрузить модули нашего приложения. Мы используем для этого SystemJS. Есть много вариантов, и нельзя сказать, что SystemJS — лучший выбор, но мы его любим, и он работает.

Специфика настройки SystemJS выходит за пределы данного туториала. Мы кратко опишем часть конфигурации в приложении ниже.

Когда Angular вызывает функцию bootstrap в boot.js, он читает метаданные AppComponent, находит селектор my-app, обнаруживает тэг с именем my-app и загружает наше приложение в этот тэг.

Скомпилируем и запустим!


Откройте окно терминала и введите следующую команду

npm start


Эта команда запускает два параллельных процесса node.

  1. Компилятор TypeScript в режиме наблюдения.
  2. Статический сервер lite-server, который загружает index.html в браузере и обновляет браузер каждый раз, когда код приложения изменяется.


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

My First Angular 2 App


Поздравляем! Вы в деле!

Если вы видите вместо этого Loading…, прочитайте приложение «Поддержка ES6 браузерами».


Внесём несколько изменений
Попробуйте изменить сообщение на «My SECOND Angular 2 app».

Компилятор TypeScript и lite-server наблюдают за вашими действиями. Они должны засечь изменение, перекомпилировать TypeScript в JavaScript, обновить вкладку браузера и отобразить обновлённое сообщение.

Это изящный способ разработки приложений!

Мы закрываем окно терминала когда мы всё сделали для того, чтобы прервать одновременно компилятор и сервер.

Финальная структура


Финальная структура нашей папки проекта должна выглядеть так:

angular2-quickstart
├── node_modules
├── app
│   ├── app.component.ts
│   └── boot.ts
├── index.html
├── package.json
└── tsconfig.json


И вот наши файлы:

app/app.component.ts
import {Component} from 'angular2/core';
@Component({
    selector: 'my-app',
    template: '

My First Angular 2 App

' }) export class AppComponent { }


app/boot.ts
import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'
bootstrap(AppComponent);



index.html

  
    Angular 2 QuickStart
    
    
    
    
    
    
    
  
  
  
    Loading...
  




package.json
{
    "name": "angular2-quickstart",
    "version": "1.0.0",
    "scripts": {
        "tsc": "tsc",
        "tsc:w": "tsc -w",
        "lite": "lite-server",
        "start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
    },
    "license": "ISC",
    "dependencies": {
        "angular2": "2.0.0-beta.0",
        "systemjs": "0.19.6",
        "es6-promise": "^3.0.2",
        "es6-shim": "^0.33.3",
        "reflect-metadata": "0.1.2",
        "rxjs": "5.0.0-beta.0",
        "zone.js": "0.5.10"
    },
    "devDependencies": {
        "concurrently": "^1.0.0",
        "lite-server": "^1.3.1",
        "typescript": "^1.7.3"
    }
}



tsconfig.json
{
    "compileroptions": {
        "target": "es5",
        "module": "system",
        "moduleresolution": "node",
        "sourcemap": true,
        "emitdecoratormetadata": true,
        "experimentaldecorators": true,
        "removecomments": false,
        "noimplicitany": false
    },
    "exclude": [
        "node_modules"
    ]
}


Заключение


Наше первое приложение делает не слишком много. Это, по сути, «Hello World» на Angular 2.

Для первого раза мы сделали всё максимально просто: написали небольшой компонент Angular, добавили немного библиотек JavaScript в index.html и запустили статический файловый сервер. В целом, это всё, что мы ожидали от «Hello World»-приложения.

У нас более серьёзные амбиции
Хорошая новость в том, что вся возня с установкой нас не касается. Возможно, мы чуть-чуть коснёмся package.json для обновления библиотек. Мы откроем index.html только если нам нужно будет добавить библиотеку или файл css-стилей.

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

Присоединяйтесь к нам в туториале «Геройский тур»!

Приложения


Остаток данной главы посвящён набору приложений, более подробно излагающих кое-какие моменты, которые мы кратко затронули выше.

Здесь нет никакого критически важного материала. Читайте дальше, если вам интересны детали.

↑ Приложение: Поддержка ES6 браузерами
Angular 2 полагается на некоторые возможности стандарта ES2015, большая часть из которых уже включена в современные браузеры. Однако некоторым браузерам (таким, как IE11), требуются полифиллы (shim) для поддержки этой функциональности. Попробуйте загрузить следующие полифиллы перед другими скриптами в index.html:




↑ Приложение: package.json
npm — это популярный менеджер пакетов для node, и многие Angular-разработчики используют его для загрузки и управления библиотеками, которые необходимы их приложениям.

Мы определили пакеты, которые нам необходимы в файле npm package.json.

Команда Angular предлагает использовать пакеты, указанные в секциях dependencies и devDependencies в этом файле:

// package.json (dependencies)
{
    "dependencies": {
        "angular2": "2.0.0-beta.0",
        "systemjs": "0.19.6",
        "es6-promise": "^3.0.2",
        "es6-shim": "^0.33.3",
        "reflect-metadata": "0.1.2",
        "rxjs": "5.0.0-beta.0",
        "zone.js": "0.5.10"
    },
    "devDependencies": {
        "concurrently": "^1.0.0",
        "lite-server": "^1.3.1",
        "typescript": "^1.7.3"
    }
}


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

В package.json может присутствовать необязательная секция scripts, в которой мы можем определить полезные команды для выполнения разработки и построения. Мы включаем несколько таких скриптов в предлагаемом нами package.json:

// package.json (scripts)
{
    "scripts": {
        "tsc": "tsc",
        "tsc:w": "tsc -w",
        "lite": "lite-server",
        "start": "concurrent \"npm run tsc:w\" \"npm run lite\" "
    }
}


Мы уже видели, как можно запустить компилятор и сервер одновременно с помощью этой команды:

npm start


Мы исполняем скрипты npm в следующем формате: npm run + название-скрипта. Вот описание того, что делают скрипты:

  • npm run tsc — запуск компилятора TypeScript на один проход
  • npm run tsc: w — запуск компилятора TypeScript в режиме наблюдения; процесс продолжает работу, перекомпилируя проект в тот момент, когда засекает изменения, внесённые в файлы TypeScript.
  • npm run lite — запускает lite-server, легковесный статический файловый сервер, написанный и поддерживаемый Джоном Папа с великолепной поддержкой приложений Angular, которые используют маршрутизацию.


↑ Приложение: Предупреждения и ошибки npm
Всё хорошо, когда любые консольные сообщения, начинающиеся с npm ERR! отсутствуют в конце работы npm install. Могут быть несколько сообщений npm WARN в течение работы команды — и это превосходный результат.

Мы часто наблюдаем сообщение npm WARN после серии gyp ERR! Игнорируйте его. Пакет может попытаться перекомпилировать себя с помощью node-gyp. Если эта попытка заканчивается неудачей, пакет восстанавливается (обычно на предыдущую версию), и всё работает.

Всё хорошо до тех пор, пока нет ни одного сообщения npm ERR! в самом конце npm install.

↑ Приложение: Конфигурация TypeScript
Мы добавили конфигурационный файл (tsconfig.json) в наш проект, чтобы объяснить компилятору, как нужно генерировать файлы JavaScript. Подробнее про tsconfig.json вы можете узнать из официальной TypeScript wiki.

Опции и флаги, которые мы добавили в файл, являются наиболее важными.

Хотелось бы немного подискутировать насчёт флага noImplicitAny. Разработчики TypeScript расходятся во мнении относительно того, должен он быть установлен как true или false. Здесь нет точного ответа, и мы всегда можем изменить флаг позже. Но наш выбор может серьёзно повлиять на крупные проекты, так что он достоин дискуссии.

Когда noImplicitAny установлен в позицию false, компилятор, если он не может вывести тип переменной в зависимости от того, как переменная используется, скрыто устанавливает тип переменной в any. Это и значит «скрытый (implicit) any».

Когда noImplicitAny установлен в позицию true, и компилятор TypeScript не может вывести тип, он всё ещё генерирует файл JavaScript, но также и отчитывается об ошибке.

В этом QuickStart и во многих других примерах этого Developer Guide мы устанавливаем noImplicitAny в позицию false.

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

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

"suppressImplicitAnyIndexErrors":true


↑ Приложение: Конфигурация SystemJS
QuickStart использует SystemJS для загрузки приложения и библиотечных модулей. Однако не забывайте, что у него есть рабочие альтернативы, такие как высоко оцениваемый сообществом webpack. SystemJS — это неплохой выбор, но мы хотим дать ясное понимание, что это лишь выбор, а не предпочтение.

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

Мы рекомендуем вам хорошо разобраться в загрузчике, который вы выберете.

Узнать больше о конфигурации SystemJS можно здесь.


Приняв во внимание эти предостережения, что мы можем сделать?





Узел packages указывает SystemJS, что делать, если он видит запрос на модуль из папки app/.

Наш QuickStart создаёт такие запросы каждый раз, когда в любом TypeScript-файле приложения обнаруживается подобный оператор импорта:

// boot.ts (часть)
import {AppComponent} from './app.component'


Обратите внимание, что наименование модуля (после from) не содержит расширения файла. Конфигурация packages задаёт SystemJS расширение по-умолчанию как 'js', то есть файл JavaScript.

Это разумно, потому что мы компилируем TypeScript в JavaScript прежде, чем запускать приложение.

В демо-примере на plunker мы компилируем в JavaScript прямо в браузере на лету. Это неплохо для демо, но это не может стать нашим выбором для разработки или релиза.

Мы рекомендуем компилировать в JavaScript в течение фазы построения перед тем, как запускать приложение, по нескольким причинам:

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


Вызов System.import заставляет SystemJS импортировать файл boot (boot.js… после компиляции boot.ts, помните?) boot — это файл, где мы просим Angular запустить приложение. Мы также отлавливаем и логируем ошибки запуска в консоль.

Все прочие модули загружаются с помощью запроса, который создаётся оператором импорта или самим Angular.

↑ Приложение: boot.ts
Загрузка платформоспецифична
Мы импортируем функцию bootstrap из angular2/platform/browser, не из angular2/core. Этому есть причина.

Мы можем назвать «ядром» только те возможности, которые одинаковы для всех целевых платформ. Действительно, многие приложения Angular могут быть запущены только в браузере, и мы будем вызывать функцию bootstrap из этой библиотеки наибольшее количество времени. Вполне «core»-фича — если мы пишем исключительно для браузера.

Но ведь вполне возможно загружать компонент в ином окружении. Мы можем загрузить его на мобильном устройстве с помощью Apache Cordova. Мы можем захотеть отрендерить начальную страницу нашего приложения на сервере для увеличения производительности или содействия SEO-продвижению.

Эти платформы требуют других вариантов bootstrap-функции, которые мы будем загружать из другой библиотеки

Зачем создавать отдельный файл boot.ts?
Файл boot.ts небольшой. Это всего лишь QuickStart. Мы вполне можем вписать эти несколько строк в файл app.component и избавить себя от излишней сложности.

Но мы так не делаем по причинам, которые, как мы верим, являются весомыми:

  1. Сделать всё правильно — это просто.
  2. Удобство тестирования.
  3. Удобство переиспользования.
  4. Разделение обязанностей.
  5. Изучение импорта и экспорта.


Это просто
Да, это дополнительный шаг и дополнительный файл. Насколько это сложно в целом?

Мы увидим, что отдельный файл boot.ts предпочтительней для большинства приложений — даже если это не столь важно для QuickStart. Давайте вырабатывать хорошие привычки сейчас, пока цена этому невысока.

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

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

Перемещение bootstrap-функции в boot.ts убирает ложную ошибку и оставляет нас с чистым файлом компонента.

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

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

Импорт/Экспорт
Когда мы писали отдельный файл boot.ts, то получили важный навык для работы с Angular: как экспортировать что-то из одного модуля и импортировать в другой. Мы будем делать много подобного, когда будем более тесно работать с Angular.

© Habrahabr.ru