После довольно удачной пробы пера с Ember Octane я решил (точнее мы с гуглотранслейтом решили) замахнутся на святое перевод туториала из официального руководства Ember.js Как вы увидите из текста, данный туториал рассчитан на самых маленьких начинающих программистов. Что не мешает ему служить опытным бойцам прекрасной отправной точкой для знакомства фреймворком. Для полного прохождения этой игры туториала вам понадобится 1-2 часа времени. После этого вы сможете оценить Ember.js в его последней редакции Octane без необходимости читать обзоры позапрошлогодней свежести  Список тем, которые покрывает туториал внушает: Если вы согласны, что это вкуснота стоит траты 1-2 часов, добро пожаловать под кат! Добро пожаловать в мир Ember! В этом туториале мы будем использовать Ember для создания приложения Super Rentals. Это будет веб-сайт для просмотра интересных мест, где можно остановиться во время вашего следующего отпуска. Проверьте готовое приложение, чтобы получить представление о масштабах проекта.  Попутно вы узнаете все, что вам нужно знать для создания базового приложения Ember. Если вы застряли в какой-то момент во время урока, не стесняйтесь скачать исходники для полного рабочего примера. Этот урок состоит из двух частей. Первая часть охватывает следующие основные понятия: Во второй части урока мы перейдем на следующий уровень, используя уже изученные концепции. В этой части вы будете устанавливать Ember CLI, использовать его для создания нового проекта Ember и добавлять базовые шаблоны и стили в свое новое приложение. К концу части у вас должна появиться целевая страница с изображением милого профессора Томстера:
 Создавая эту страницу, вы научитесь: Вы можете установить последнюю версию Ember CLI, выполнив следующую команду: Чтобы убедиться, что ваша установка прошла успешно, запустите: Если отображается номер версии, вы готовы к работе. Мы можем создать новый проект, используя команду Ember CLI new. Используйте паттерн ember new <project-name>. В нашем случае название проекта будет super-rentals: Эта команда создаст для нас новую папку под названием super-rentals. Мы можем перейти к ней с помощью команды cd. В оставшейся части туториала все команды должны выполняться в папке super-rentals. Эта папка имеет следующую структуру: По мере продвижения по уроку мы узнаем о предназначении этих файлов и папок. А пока, просто знайте, что большую часть времени мы будем работать в папке app. Ember CLI поставляется с множеством различных команд для различных задач разработки, таких как команда ember new которую мы видели ранее. Он также поставляется с сервером разработки, который мы можем запустить с помощью команды ember server : Сервер разработки отвечает за компиляцию нашего приложения. Также в него встроен веб-сервер, поставляющий файлы браузеру. Загрузка может занять некоторое время. Как только он заработает, откройте ваш любимый браузер и перейдите по адресу http://localhost:4200. Вы должны увидеть следующую страницу приветствия:
 Вы можете выйти из сервера разработки в любое время, набрав Ctrl + C (для MacOS Cmd + C) в окне терминала, где работает ember server. То есть, нажимая клавишу «C» на клавиатуре, одновременно удерживая клавишу «Ctrl». Как только он остановился, вы можете запустить его снова с помощью той же команды ember server. Мы рекомендуем открыть два окна терминала: одно для запуска сервера в фоновом режиме, другое для ввода других команд консоли Ember. Сервер разработки имеет функцию под названием live reload, которая отслеживает изменения файлов в вашем приложении, автоматически перекомпилирует все и обновляет все открытые страницы браузера. Это очень удобно при разработке, поэтому давайте попробуем! Как указывалось в тексте на странице приветствия, исходный код страницы находится в app/templates/application.hbs. Давайте попробуем отредактировать этот файл и заменить его собственным контентом:

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

Когда вы закончите экспериментировать, удалите файл app/templates/application.hbs. Он нам не понадобится еще какое-то время. Мы добавим его позже. Опять же, если у вас по-прежнему открыта вкладка браузера, ваша вкладка автоматически повторно отобразит пустую страницу, как только вы удалите файл. Это отражает тот факт, что у нас больше нет шаблона приложения в нашем приложении. Создайте файл app/templates/index.hbs и вставьте следующую разметку.

Если вы думаете: «Эй, это похоже на HTML!», То вы абсолютно правы! В своей простейшей форме шаблоны Ember — это просто HTML. Если вы уже знакомы с HTML, вы должны чувствовать себя здесь как дома. Конечно, в отличие от HTML, шаблоны Ember могут сделать гораздо больше, чем просто отображать статический контент. Мы скоро увидим это в действии. После сохранения файла ваша вкладка браузера должна автоматически обновиться, показывая нам приветственное сообщение, над которым мы только что работали.  Прежде чем делать что-то еще, давайте добавим немного стиля в наше приложение. Мы тратим достаточно времени, глядя на экран компьютера, поэтому мы должны защитить свое зрение от голой HTML разметки! К счастью, наш дизайнер прислал нам немного CSS для использования, поэтому мы можем загрузить файл таблицы стилей и скопировать его в app/styles/app.css. В этом файле есть все стили, которые нам нужны для создания остальной части приложения. Если вы знакомы с CSS, не стесняйтесь настраивать эти стили по своему вкусу! Просто имейте в виду, что вы можете увидеть некоторые визуальные различия в будущем, если вы решите это сделать. Когда вы будете готовы, сохраните файл CSS; наш надежный сервер разработки должен сразу же его заберет и обновить нашу страницу. Нет больше голого HTML контента!  Чтобы соответствовать макету от нашего дизайнера, нам также нужно скачать изображение teaching-tomster.png, на которое ссылается наш CSS-файл: Как мы узнали ранее, конвенция Ember заключается в размещении вашего исходного кода в папке app. Для других ресурсов, таких как изображения и шрифты, существует папка public. Мы будем следовать этому соглашению, загрузив файл изображения и сохранив его в public/assets/images/teaching-tomster.png . И Ember CLI, и сервер разработки понимают эти соглашения о папках и автоматически делают эти файлы доступными для браузера. Вы можете подтвердить это, перейдя по http://localhost:4200/assets/images/teaching-tomster.png. Изображение также должно отображаться на странице приветствия, над которой мы работаем. Если при обновлении изображение все-таки не появилось, попробуйте выполнить обновление вручную, чтобы браузер подобрал новый файл.
 В этой части вы создадите первые несколько страниц вашего приложения Ember и установите ссылки между ними. К концу этой главы у вас должны появиться две новые страницы — страница "O нас" и страница "Контакты". Эти страницы будут связаны с вашей стартовой страницей:


 Создавая эти страницы, вы узнаете об: После создания нашей первой страницы, давайте добавим еще одну! На этот раз мы хотели бы, чтобы страница размещалась по URL-адресу /about. Для этого нам нужно сообщить Ember о нашем плане добавить страницу в этом месте. В противном случае Ember будет считать, что мы посетили неверный URL! Местом для управления доступными страницами является маршрутизатор. Откройте app/router.js и внесите следующие изменения:  Это добавляет маршрут с именем «about», который по умолчанию обслуживается в URL-адресе /about. Теперь мы можем создать новый файл app/templates/about.hbs со следующим содержимым:  Чтобы увидеть это в действии, перейдите по http://localhost:4200/about.  Вот и готова наша вторая страница! Продолжаем! Давайте добавим нашу третью страницу. На этот раз все немного по-другому. Все в компании называют это страницей «контактов». Тем не менее, старый веб-сайт, который мы заменяем, уже имеет аналогичную страницу, которая обслуживается по устаревшему URL-адресу /getting-in-touch. Мы хотим сохранить существующие URL-адреса для нового веб-сайта, но нам не нужно вводить getting-in-touch всему новому коду! К счастью, мы можем поступить лучше:  Здесь мы добавили маршрут contact, но явно указали путь для маршрута. Это позволяет нам сохранить устаревший URL, но использовать новое, более короткое имя для маршрута, а также имя файла шаблона. Говоря о шаблоне, давайте создадим и его. Мы добавим файл app/templates/contact.hbs с содержимым:  Ember придерживается жестких соглашений и разумных настроек по умолчанию — если бы мы начинали с нуля, мы бы не возражали против дефолтного URL /contact. Однако, если настройки по умолчанию не работают для нас, это не проблема. Мы можем настроить Ember для наших нужд! После того как вы добавили маршрут и шаблон выше, у нас должна появиться новая страница по адресу http://localhost:4200/getting-in-touch.  Мы приложили столько усилий, чтобы сделать эти страницы, но нам нужно, чтобы люди могли их найти! В Интернете для этого используют гиперссылки или для краткости просто ссылки. Ember предлагает отличную поддержку для URL-адресов «из коробки». Мы можем просто связать наши страницы вместе, используя тег <a> с соответствующим href. Однако щелчок по этим ссылкам потребует от браузера полного обновления страницы, а это значит, что ему придется вернуться на сервер, чтобы получить страницу, а затем снова загрузить все с нуля. С Ember мы можем добиться большего! Вместо простого старого тега <a> Ember предлагает альтернативу <LinkTo>. Например, вот как вы могли бы использовать его на страницах, которые мы только что создали:
   Давайте разберем подробнее, что мы сейчас добавили.  <LinkTo> является примером компонента в Ember — вы можете отличить его от обычных тегов HTML, поскольку они начинаются с заглавной буквы. Наряду с обычными тегами HTML, компоненты являются теми кирпичиками, которые мы можем использовать для создания пользовательского интерфейса приложения. Позже у нас будет гораздо больше информации о компонентах, но сейчас вы можете думать о них как о способе предоставления пользовательских тегов, дополняющих встроенные в браузеры теги. Часть @route=... — это то, как мы передаем аргументы в компонент. Здесь мы используем этот аргумент, чтобы указать, какой маршрут мы хотим связать. (Обратите внимание, что это должно быть имя маршрута, а не путь, поэтому мы указали "about" вместо "/about" и "contact" вместо "/getting-in-touch" .) В дополнение к аргументам компоненты также могут принимать обычные атрибуты HTML. В нашем примере мы добавили класс "button" для стилизации, но мы могли бы также указать другие атрибуты, которые мы посчитаем нужными, такие как атрибут role ARIA. Они передаются без символа @ ( class=... в отличие от @class=...), поэтому Ember будет знать, что они являются обычными HTML-атрибутами. Под капотом компонент <LinkTo> генерирует для нас обычный тег <a> с соответствующей href для конкретного маршрута. Этот тег <a> прекрасно работает с программами чтения с экрана, а также позволяет нашим пользователям добавить ссылку в закладки или открыть ее в новой вкладке. Однако при нажатии на одну из этих специальных ссылок Ember будет перехватывать клик мышки, отображать содержимое для новой страницы и обновлять URL-адрес — все это выполняется локально, без ожидания сервера. Это позволяет избежать полного обновления страницы. Мы узнаем больше о том, как все это работает в ближайшее время. А пока идем дальше и нажимаем на ссылку в браузере. Вы заметили, как это быстро происходят переходы? Поздравляем, вы уже на полпути к тому, чтобы стать мастером по созданию страниц! В этой части вы будете использовать встроенную среду тестирования Ember, чтобы написать несколько автоматических тестов для вашего приложения. В результате у нас будет автоматизированный набор тестов, который мы сможем запустить, чтобы убедиться, что наше приложение работает правильно:  В процессе вы узнаете о: Мы уже достигли многого! Подведем итоги — мы начали с чистого листа, добавили несколько страниц контента, стилизовали все, чтобы выглядело красиво, добавили изображение Томстера, добавили ссылки между нашими страницами и, что удивительно, все заработало! Но действительно ли мы уверены, что все на самом деле работает? Конечно, мы немного покликали, чтобы убедиться, что все выглядит так, как ожидалось. Но уверены ли мы, что проверили каждую страницу после самого последнего внесенного нами изменения? В конце концов, большинство из нас имеют опыт (или услышали ужасные истории), когда маленькое изменение в одной области приложения непреднамеренно ломало что-то в другой части. Даже если мы ничего там не меняли (и соответственно, не проверяли потом). Допустим, мы можем написать список проверок и проверить его после внесения изменений на нашем сайте. Но, конечно, это выйдет из-под контроля, когда мы добавим больше функций в наше приложение. Он также очень быстро устареет. Поэтому такие повторяющиеся задачи лучше оставить роботам. Хм, роботы. Это идея! Что если мы сможем написать этот контрольный список и просто заставить компьютер проверить все за нас? Я думаю, что мы только что изобрели идею автоматизированного тестирования! Ладно, может быть, мы не были первыми, кто придумал эту концепцию, но мы независимо ее обнаружили, поэтому мы все еще заслуживаем небольшой похвалы) Как только мы закончим поглаживать себя по голове или доедим пирожок с полки, выполним следующую команду в терминале: В Ember CLI это называется командой генератора. Генераторы автоматически создают файлы для нас на основе соглашений Ember и заполняют их соответствующим стандартным содержимым, подобно тому, как ember new изначально создала для нас скелетное приложение. Обычно он следует шаблону ember generate <type> <name>, где <type> — это то, что мы генерируем, а <name> — то, как мы хотим это назвать. В данном случае мы сгенерировали приемочный тест, расположенный по адресу tests/acceptance/super-rentals-test.js. Конечно, использовать генераторы не обязательно; мы могли бы сами создать файл, который бы сделал то же самое. Но генераторы, безусловно, избавляют нас от ненужной умственной нагрузки на поиск правильной папки и имени, а также времени на набор содержимого. Взгляните на файл приемочного теста и убедитесь сами. Приемочные тесты, являются одним из видов автоматизированного тестирования, который находится в нашем распоряжении в Ember. Позже мы узнаем о других типах, но что делает приемочные тесты уникальными, так это то, что они тестируют наше приложение как бы с точки зрения пользователя — это автоматизированная версия тестирования «нажми и посмотри, работает ли», которое мы делали ранее самостоятельно. Давайте откроем сгенерированный тестовый файл и заменим шаблонный тест нашим собственным:  Сначала мы проинструктировали тестового робота перейти к корневому URL / нашего приложения с помощью тестового помощника (test helper) visit предоставленного Ember. Это сродни тому, что мы набрав http://localhost:4200/ в адресной строке браузера нажали клавишу enter. Поскольку загрузка страницы займет некоторое время, это называется асинхронным шагом, поэтому нам нужно будет сказать тестовому роботу ждать, используя ключевое слово JavaScript await. Таким образом, он будет ждать, пока страница полностью не загрузится, прежде чем перейти к следующему шагу. Это почти всегда то поведение, которое мы хотим получить, поэтому мы почти всегда будем использовать await и visit как пару. Это относится и к другим видам симулированного взаимодействия, например, к нажатию на кнопку или ссылку, поскольку все они требуют времени для завершения. Хотя иногда эти действия могут показаться нам незаметно быстрыми, мы должны помнить, что у нашего тестового робота действительно, очень быстрые руки, в чем мы убедимся через мгновение. После перехода к URL / и ожидания решения проблемы мы проверяем, соответствует ли текущий URL ожидаемому URL ( / ). Мы можем использовать currentURL тест-помощник currentURL, а также equal утверждение. Вот как мы кодируем наш «контрольный список» в код. Указав или заявив, как все должно себя вести, мы будем предупреждены, если наше приложение не будет вести себя так, как мы ожидаем. Затем мы подтвердили, что на странице есть тег <h2>, содержащий текст «Добро пожаловать в Super Rentals!». Проверка этого, означает, что мы можем быть совершенно уверены, что шаблон был отображен без ошибок. Затем мы искали ссылку с текстом «About Us», расположенную с помощью селектора CSS .jumbo a.button. Это тот же синтаксис, который мы использовали в нашей таблице стилей, что означает «заглянуть внутрь тега с классом jumbo для тега <a> с классом button». Это соответствует структуре HTML в нашем шаблоне. Как только существование этого элемента на странице подтвердилось, мы попросили тестового робота нажать на эту ссылку. Как упоминалось выше, это взаимодействие с пользователем, поэтому к нему необходимо добавить ключевое слово await. Наконец, мы убеждаемся, что нажатие на ссылку должно привести нас к URL-адресу /about. Мы можем запустить наш автоматический тест, запустив тестовый сервер с помощью команды ember test --server или ember t -s для краткости. Этот сервер ведет себя во многом как сервер разработки, но он запущен для наших тестов. Он может автоматически открыть окно браузера и перейти к тестовому интерфейсу. Или вы можете открыть http://localhost:7357/ самостоятельно. Если вы посмотрите очень внимательно, вы увидите, как наш тестовый робот бродит по нашему приложению и нажимает на ссылки (это происходит очень быстро):  Здесь важно то, что тест, который мы написали, прошел, а это означает, что все работает именно так, как мы ожидаем, и в пользовательском интерфейсе теста все зеленое и счастливое. Если вы хотите, вы можете перейти к index.hbs, удалить компонент <LinkTo> и посмотреть, как все будет выглядеть, когда у нас будет неудачный (failing) тест:  Не забудьте вернуть эту строку обратно! Давайте попрактикуемся в том, что мы узнали, добавив тесты для оставшихся страниц: 
 Как и на сервере разработки, пользовательский интерфейс теста должен автоматически перезагружаться и повторно запускать весь набор тестов при сохранении файлов. Рекомендуется держать эту страницу открытой при разработке приложения. Таким образом, вы получите немедленную обратную связь, если случайно что-то сломаете.  В оставшейся части руководства мы продолжим добавлять дополнительные автоматизированные тесты по мере разработки новых функций. Тестирование не является обязательным, но настоятельно рекомендуется (от переводчика: особенно, когда вы дописываете или переписываете ваше приложение) Тесты не влияют на функциональность вашего приложения, они просто защищают его от регрессий, что просто является способом заметить «случайные поломки». Если вы спешите, вы можете пропустить разделы тестирования в этом учебном пособии и при этом продолжать следить за всем остальным. Но разве вы не находите супер удовлетворяющим — странно удовлетворяющим — наблюдать, как робот шустро бегает по страницам и выдает в конце зеленую полосочку? В этой части вы проведете рефакторинг существующих шаблонов для использования компонентов. Мы также добавим панель навигации для всего сайта: 
При этом вы узнаете об: В предыдущей части мы получили небольшое представление о компонентах при использовании <LinkTo> для соединения наших страниц. Напомним, что мы говорили, что компоненты — это способ создания пользовательских тегов Ember в дополнение к встроенным тегам HTML из браузера. Теперь мы собираемся создать наши собственные компоненты! В ходе разработки приложения довольно часто используется один и тот же элемент пользовательского интерфейса в разных частях приложения. Например, мы использовали один и тот же заголовок "jumbo" на всех трех страницах. На каждой странице мы работали, следуя одной и той же базовой структуре:  Поскольку кода не так много, может показаться, что дублировать эту структуру на каждой странице не составляет большого труда. Однако, если бы наш дизайнер захотел, чтобы мы внесли изменения в заголовок, мы должны были бы найти и обновить каждую копию этого кода. Когда наше приложение станет больше, это станет еще более серьезной проблемой. Компоненты являются идеальным решением для этого. В своей основной форме компонент — это просто часть шаблона, на которую можно ссылаться по имени. Давайте начнем с создания нового файла в app/components/jumbo.hbs с разметкой для заголовка «jumbo»:  Вот и все, мы создали наш первый компонент! Теперь мы можем вызвать этот компонент в любом месте нашего приложения, используя <Jumbo> качестве имени тега. При вызове компонента Ember заменяет тег компонента содержимым, найденным в шаблоне компонента. Как и в случае с обычными HTML-теги, распространено передавать контент компонентам, например, <Jumbo>some content</Jumbo>. Мы можем обработать это с помощью ключевого слова {{yield}}, которое будет заменено содержимым, которое было передано компоненту. Давайте попробуем это, отредактировав шаблон индекса:  После сохранения изменений ваша страница должна автоматически перезагрузиться, и, вуаля… ничего не изменилось! Ну, это именно то, что мы хотели! Мы успешно реорганизовали наш индексный шаблон для использования компонента <Jumbo>, и все по-прежнему работает, как и ожидалось.   И тесты проходят!  Давайте сделаем то же самое для двух других наших страниц.   После сохранения все должно выглядеть точно так же, как и раньше, и все тесты должны пройти. Хотя в этом случае это может не сэкономить много символов, инкапсуляция реализации заголовка «jumbo» в его собственный компонент делает шаблон более читаемым, поскольку позволяет читателю сосредоточиться на вещах, которые уникальны для данной страницы. Кроме того, если нам нужно внести изменения в заголовок, мы можем сделать это в одном месте. Не стесняйтесь попробовать! Прежде чем мы перейдем к следующему аспекту, давайте напишем автоматический тест для нашего компонента <Jumbo>. Запустите эту команду в своем терминале: Здесь мы использовали генератор для генерации теста компонента (component test), также известного как тест рендеринга (rendering test). Они используются для визуализации и тестирования одного компонента за раз. Это в отличие от приемочных тестов, которые мы написали ранее, которые должны отображать целые страницы контента. Давайте заменим шаблон кода, который был сгенерирован для нас, нашим собственным тестом:  Вместо перехода по URL-адресу мы начинаем тестирование с отображения нашего компонента <Jumbo> на тестовой странице. Это полезно, потому что в противном случае может потребоваться много настройки и взаимодействия, чтобы просто попасть на страницу, где используется ваш компонент. Тестирование компонентов позволяет нам пропустить все это и сосредоточиться исключительно на тестировании компонента в отдельности. Как и при посещении и клике, который мы использовали ранее, рендеринг также является асинхронным шагом, поэтому нам нужно связать его с ключевым словом await. Кроме этого, остальная часть теста очень похожа на приемочные тесты, которые мы написали в предыдущей главе. Убедитесь, что тест проходит, проверив пользовательский интерфейс тестов в браузере.  Мы уже некоторое время проводим рефакторинг нашего существующего кода, поэтому давайте сменим род деятельности и добавим новую фичу: панель навигации для всего сайта. Создадим компонент <NavBar> в app/components/nav-bar.hbs:  Далее добавим наш компонент  вверху каждой страницы:
    Вуаля, мы сделали еще один компонент!  В браузере все выглядит отлично, но, как мы знаем, мы никогда не можем быть слишком уверены. Итак, давайте напишем несколько тестов! Но каких? Мы могли бы написать тест компонента для <NavBar> сам по себе, как мы только что сделали для компонента <Jumbo>. Однако, поскольку задача <NavBar> состоит в том, чтобы ориентировать нас по приложению, нет особого смысла тестировать этот конкретный компонент изолированно. Вернемся же к написанию приемочных тестов! 
 Мы обновили существующие тесты, чтобы утверждать, что на каждой странице существует элемент <nav>. Это важно для доступности (accessibility), так как программы чтения с экрана будут использовать этот элемент для обеспечения навигации. Также мы добавили новый тест, который проверяет поведение ссылок <NavBar> . Все тесты должны пройти в этот момент!  Прежде чем мы перейдем к следующей функции, есть еще одна вещь, которую мы могли бы улучшить. Поскольку <NavBar> используется для навигации по всему сайту, его действительно необходимо отображать на каждой странице приложения. До сих пор мы добавляли компонент на каждую страницу вручную. Это подвержено ошибкам, так как мы можем легко забыть сделать это при следующем добавлении новой страницы. Мы можем решить эту проблему, переместив панель навигации в специальный шаблон под названием application.hbs. Возможно, вы помните, что он был сгенерирован для нас, когда мы впервые создали приложение, но тогда мы его удалили. Теперь пришло время вернуть! Этот шаблон отличается тем, что у него нет собственного URL-адреса, и на него нельзя перейти самостоятельно. Скорее, он используется для указания общего макета, который используется всеми страницами вашего приложения. Это отличное место для размещения элементов пользовательского интерфейса, таких как навигационная панель и нижний колонтитул (footer) сайта. Пока мы это делаем, мы также добавим элемент контейнера, который будет охватывать всю страницу, как того требует наш дизайнер для стилизации.     Ключевое слово {{outlet}} обозначает место, где должны отображаться страницы нашего сайта, аналогично ключевому слову {{yield}}, которое мы использовали ранее. Так намного приятнее! Мы можем запустить наш набор тестов, который подтверждает, что все работает после нашего рефакторинга. И мы готовы перейти к следующей фиче!  На этом часть 1.1 заканчивается. Как посадить самолет Продолжение мы с гуглотранслейтом расскажем в следующей серии. UPDATE: Благодарю пользователя MK1301 за легкую редактуру.