Создание веб-приложений с помощью Yeoman и Polymer

Создайте свои веб-приложения с помощью современных инструментов

Адди Османи
Addy Osmani

Введение

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

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

Йомен

Знакомьтесь, Йо, Грант и Бауэр

Йомен — это человек в шляпе, у которого есть три инструмента для повышения вашей продуктивности:

  • yo — это инструмент формирования лесов, который предлагает экосистему каркасов для конкретной платформы, называемых генераторами, которые можно использовать для выполнения некоторых утомительных задач, о которых я упоминал ранее.
  • grunt используется для создания, предварительного просмотра и тестирования вашего проекта благодаря помощи задач, курируемых командой Yeoman и grunt-contrib .
  • Bower используется для управления зависимостями, поэтому вам больше не придется вручную загружать и управлять своими скриптами.

Всего одной-двумя командами Yeoman может написать шаблонный код для вашего приложения (или отдельные части, такие как модели), скомпилировать Sass, свернуть и объединить CSS, JS, HTML и изображения и запустить простой веб-сервер в вашем текущем каталоге. Он также может запускать ваши модульные тесты и многое другое.

Вы можете установить генераторы из Node Packaged Modules (npm), и сейчас доступно более 220 генераторов , многие из которых были написаны сообществом открытого исходного кода. Популярные генераторы включают генератор-угловой , генератор-базовый и генератор-эмбер .

Домашняя страница Йомена

Установив последнюю версию Node.js , подойдите к ближайшему терминалу и запустите:

$ npm install -g yo

Вот и все! Теперь у вас есть Yo, Grunt и Bower, и вы можете запускать их прямо из командной строки. Вот результат запуска yo :

Установка Йомена

Полимерный генератор

Как я упоминал ранее, Polymer — это библиотека полифилов и сахара, которая позволяет использовать веб-компоненты в современных браузерах. Проект позволяет разработчикам создавать приложения, используя платформу завтрашнего дня, и информировать W3C о местах, где текущие характеристики могут быть дополнительно улучшены.

Домашняя страница полимерного генератора

генератор-полимер — это новый генератор, который помогает создавать приложения Polymer с помощью Yeoman, позволяя легко создавать и настраивать (настраиваемые) элементы Polymer через командную строку и импортировать их с помощью импорта HTML. Это экономит ваше время, поскольку вы пишете шаблонный код за вас.

Затем установите генератор Polymer, запустив:

$ npm install generator-polymer -g

Вот и все. Теперь ваше приложение обладает сверхспособностями веб-компонентов!

В нашем недавно установленном генераторе есть несколько конкретных функций, к которым у вас будет доступ:

  • polymer:element используется для создания новых отдельных полимерных элементов. Например: yo polymer:element carousel
  • polymer:app используется для создания исходного файла index.html, Gruntfile.js, содержащего конфигурацию времени сборки для вашего проекта, а также задачи Grunt и структуру папок, рекомендованную для проекта. Это также даст вам возможность использовать Sass Bootstrap для стилей вашего проекта.

Давайте создадим приложение Polymer

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

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

Для начала перейдите в терминал, создайте новый каталог и перейдите в него, используя mkdir my-new-project && cd $_ . Теперь вы можете запустить свое приложение Polymer, запустив:

$ yo polymer
Создание приложений из полимеров

При этом вы получите последнюю версию Polymer от Bower и создадите index.html, структуру каталогов и задачи Grunt для вашего рабочего процесса. Почему бы не выпить кофе, пока мы ждем, пока приложение завершит подготовку?

Хорошо, теперь мы можем запустить grunt server , чтобы просмотреть, как выглядит приложение:

Грант-сервер

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

Далее давайте создадим новый элемент Polymer, который будет представлять публикацию в блоге.

$ yo polymer:element post
Создать элемент публикации

Йоман задает нам несколько вопросов, например, хотим ли мы включить конструктор или использовать HTML-импорт для включения элемента post в index.html . Давайте пока скажем «Нет» первым двум вариантам и оставим третий вариант пустым.

$ yo polymer:element post

[?] Would you like to include constructor=''? No

[?] Import to your index.html using HTML imports? No

[?] Import other elements into this one? (e.g 'another_element.html' or leave blank)

    create app/elements/post.html

Это создаст новый элемент Polymer в каталоге /elements с именем post.html:

<polymer-element name="post-element"  attributes="">

    <template>

    <style>
        @host { :scope {display: block;} }
    </style>

    <span>I'm <b>post-element</b>. This is my Shadow DOM.</span>

    </template>

    <script>

    Polymer('post-element', {

        //applyAuthorStyles: true,

        //resetStyleInheritance: true,

        created: function() { },

        enteredView: function() { },

        leftView: function() { },

        attributeChanged: function(attrName, oldVal, newVal) { }

    });

    </script>

</polymer-element>

Это содержит:

Работа с реальным источником данных

Нашему блогу понадобится место для написания и чтения новых сообщений. Чтобы продемонстрировать работу с реальным сервисом данных, мы собираемся использовать API таблиц Google Apps . Это позволяет нам легко читать содержимое любой электронной таблицы, созданной с помощью Google Docs.

Давайте настроим эту настройку:

  1. В своем браузере (для этих действий рекомендуется использовать Chrome) откройте эту таблицу Документов Google. Он содержит образцы данных публикации в следующих полях:

    • ИДЕНТИФИКАТОР
    • Заголовок
    • Автор
    • Содержание
    • Дата
    • Ключевые слова
    • Электронная почта (автора)
    • Слаг (для URL-адреса вашего сообщения)
  2. Перейдите в меню «Файл» и выберите «Создать копию» , чтобы создать собственную копию электронной таблицы. Вы можете редактировать контент на досуге, добавляя или удаляя сообщения.

  3. Снова перейдите в меню «Файл» и выберите «Опубликовать в Интернете» .

  4. Нажмите начать публикацию

  5. В разделе «Получить ссылку на опубликованные данные» из последнего текстового поля скопируйте ключевую часть предоставленного URL-адреса. Выглядит это так: https://docs.google.com/spreadsheet/ccc?key=0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc#gid=0

  6. Вставьте ключ в следующий URL-адрес, где написано «ваш ключ идет здесь» : https://spreadsheets.google.com/feeds/list/your-key-goes-here/od6/public/values?alt=json- в скрипте&обратный вызов= . Пример использования приведенного выше ключа может выглядеть так: https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script .

  7. Вы можете вставить URL-адрес в свой браузер и перейти к нему, чтобы просмотреть версию содержимого вашего блога в формате JSON. Запишите URL-адрес, а затем потратьте немного времени на просмотр формата этих данных, так как вам придется перебирать его, чтобы позже отобразить на экране.

Вывод JSON в вашем браузере может выглядеть немного устрашающе, но не волнуйтесь! На самом деле нас интересуют только данные для ваших сообщений.

API Google Spreadsheets выводит каждое поле в таблице вашего блога со специальным префиксом post.gsx$ . Например: post.gsx$title.$t , post.gsx$author.$t , post.gsx$content.$t и так далее. Когда мы перебираем каждую «строку» в нашем выводе JSON, мы ссылаемся на эти поля, чтобы получить соответствующие значения для каждого сообщения.

Теперь вы можете редактировать свой новый элемент сообщения, созданный в шаблонах, чтобы привязать части разметки к данным в вашей электронной таблице. Для этого мы вводим атрибут post , который будет считывать заголовок сообщения, автора, содержание и другие поля, которые мы создали ранее. Атрибут selected (который мы заполним позже) используется для отображения сообщения только в том случае, если пользователь переходит к правильному фрагменту сообщения.

<polymer-element name="post-element" attributes="post selected">

    <template>

    <style>
        @host { :scope {display: block;} }
    </style>

        <div class="col-lg-4">

            <template if="[[post.gsx$slug.$t === selected]]">

            <h2>
                <a href="#[[post.gsx$slug.$t]]">
                [[post.gsx$title.$t  ]]
                </a>
            </h2>

            <p>By [[post.gsx$author.$t]]</p>

            <p>[[post.gsx$content.$t]]</p>

            <p>Published on: [[post.gsx$date.$t]]</p>

            <small>Keywords: [[post.gsx$keywords.$t]]</small>

            </template>

        </div>

    </template>

    <script>

    Polymer('post-element', {

        created: function() { },

        enteredView: function() { },

        leftView: function() { },

        attributeChanged: function(attrName, oldVal, newVal) { }

    });

    </script>

</polymer-element>

Далее, давайте создадим элемент blog, который будет содержать как коллекцию сообщений, так и макет вашего блога, запустив yo polymer:element blog .

$ yo polymer:element blog

[?] Would you like to include constructor=''? No

[?] Import to your index.html using HTML imports? Yes

[?] Import other elements into this one? (e.g 'another_element.html' or leave blank) post.html

    create app/elements/blog.html

На этот раз мы импортируем блог в index.html, используя импорт HTML, так, как мы хотим, чтобы он отображался на странице. В частности, для третьего приглашения мы указываем post.html в качестве элемента, который хотим включить.

Как и раньше, создается новый файл элемента (blog.html) и добавляется в /elements, на этот раз импортируя post.html и включая <post-element> в тег шаблона:

<link rel="import" href="post.html">

<polymer-element name="blog-element"  attributes="">

    <template>

    <style>
        @host { :scope {display: block;} }
    </style>

    <span>I'm <b>blog-element</b>. This is my Shadow DOM.</span>

        <post-element></post-element>

    </template>

    <script>

    Polymer('blog-element', {

        //applyAuthorStyles: true,

        //resetStyleInheritance: true,

        created: function() { },

        enteredView: function() { },

        leftView: function() { },

        attributeChanged: function(attrName, oldVal, newVal) { }

    });

    </script>

</polymer-element>

Поскольку мы запросили импорт элемента блога с помощью импорта HTML (способ включения и повторного использования HTML-документов в других HTML-документах) в наш индекс, мы также можем проверить, что он был правильно добавлен в документ <head> :

<!doctype html>
    <head>

        <meta charset="utf-8">

        <meta http-equiv="X-UA-Compatible" content="IE=edge">

        <title></title>

        <meta name="description" content="">

        <meta name="viewport" content="width=device-width">

        <link rel="stylesheet" href="styles/main.css">

        <!-- build:js scripts/vendor/modernizr.js -->

        <script src="bower_components/modernizr/modernizr.js"></script>

        <!-- endbuild -->

        <!-- Place your HTML imports here -->

        <link rel="import" href="elements/blog.html">

    </head>

    <body>

        <div class="container">

            <div class="hero-unit" style="width:90%">

                <blog-element></blog-element>

            </div>

        </div>

        <script>
        document.addEventListener('WebComponentsReady', function() {
            // Perform some behaviour
        });
        </script>

        <!-- build:js scripts/vendor.js -->

        <script src="bower_components/polymer/polymer.min.js"></script>

        <!-- endbuild -->

</body>

</html>

Фантастика.

Добавление зависимостей с помощью Bower

Далее давайте отредактируем наш элемент, чтобы использовать служебный элемент Polymer JSONP для чтения в Posts.json. Вы можете получить адаптер, клонировав репозиторий с помощью git, или установить polymer-elements через Bower, запустив bower install polymer-elements .

Зависимости Бауэра

Если у вас есть утилита, вам нужно будет включить ее в качестве импорта в элемент blog.html с помощью:

<link rel="import" href="../bower_components/polymer-jsonp/polymer-jsonp.html">

Затем добавьте тег для него и укажите url нашей таблицы сообщений в блоге, полученной ранее, добавив &callback= в конец:

<polymer-jsonp auto url="https://spreadsheets.google.com/feeds/list/your-key-value/od6/public/values?alt=json-in-script&callback=" response="[[posts]]"></polymer-jsonp>

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

<!-- Table of contents -->

<ul>

    <template repeat="[[post in posts.feed.entry]]">

    <li><a href="#[[post.gsx$slug.$t]]">[[post.gsx$title.$t]]</a></li>

    </template>

</ul>

Второй визуализирует один экземпляр post-element для каждой найденной записи, соответствующим образом передавая ему содержимое сообщения. Обратите внимание, что мы передаем атрибут post , представляющий содержимое сообщения для одной строки электронной таблицы, и selected атрибут, который мы заполним маршрутом.

<!-- Post content -->

<template repeat="[[post in posts.feed.entry]]">

    <post-element post="[[post]]" selected="[[route]]"></post-element>

</template>

Атрибут repeat , который вы видите в нашем шаблоне, создает и поддерживает экземпляр с [[ привязками ]] для каждого элемента в коллекции массивов наших сообщений, когда он предоставляется.

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

Теперь, чтобы получить текущий [[route]] заполненный, мы собираемся схитрить и использовать библиотеку под названием Flatiron Director, которая привязывается к [[route]] всякий раз, когда изменяется хэш URL-адреса.

К счастью, есть элемент Polymer (часть пакета more-elements ), который мы можем использовать для него. После копирования в каталог /elements мы можем сослаться на него с помощью <flatiron-director route="[[route]]" autoHash></flatiron-director> , указав route как свойство, к которому мы хотим привязаться, и указать ему автоматически прочитать значение любых изменений хеша (autoHash).

Теперь, сложив все вместе, мы получаем:

    <link rel="import" href="post.html">

    <link rel="import" href="polymer-jsonp/polymer-jsonp.html">

    <link rel="import" href="flatiron-director/flatiron-director.html">

    <polymer-element name="blog-element"  attributes="">

      <template>

        <style>
          @host { :scope {display: block;} }
        </style>

        <div class="row">

          <h1><a href="/#">My Polymer Blog</a></h1>

          <flatiron-director route="[[route]]" autoHash></flatiron-director>

          <h2>Posts</h2>

          <!-- Table of contents -->

          <ul>

            <template repeat="[[post in posts.feed.entry]]">

              <li><a href="#[[post.gsx$slug.$t]]">[[post.gsx$title.$t]]</a></li>

            </template>

          </ul>

          <!-- Post content -->

          <template repeat="[[post in posts.feed.entry]]">

            <post-element post="[[post]]" selected="[[route]]"></post-element>

          </template>

        </div>

        <polymer-jsonp auto url="https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdHVQUGd2M2Q0MEZnRms3c3dDQWQ3V1E/od6/public/values?alt=json-in-script&callback=" response="[[posts]]"></polymer-jsonp>

      </template>

      <script>

        Polymer('blog-element', {

          created: function() {},

          enteredView: function() { },

          leftView: function() { },

          attributeChanged: function(attrName, oldVal, newVal) { }

        });

      </script>

    </polymer-element>
Полимерное приложение

Ву! Теперь у нас есть простой блог, который считывает данные из JSON и использует два элемента Polymer, созданные с помощью Yeoman.

Работа со сторонними элементами

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

Домашняя страница пользовательских элементов

Скопируйте исходные коды элементов gravatar в каталог /elements , включите их посредством импорта HTML в post.html, а затем добавьте в свой шаблон, передав поле электронной почты из нашей таблицы в качестве источника имени пользователя. Бум!

<link rel="import" href="gravatar-element/src/gravatar.html">

<polymer-element name="post-element" attributes="post selected">

    <template>

    <style>
        @host { :scope {display: block;} }
    </style>

        <div class="col-lg-4">

            <template if="[[post.gsx$slug.$t === selected]]">

            <h2><a href="#[[post.gsx$slug.$t]]">[[post.gsx$title.$t]]</a></h2>

            <p>By [[post.gsx$author.$t]]</p>

            <gravatar-element username="[[post.gsx$email.$t]]" size="100"></gravatar-element>

            <p>[[post.gsx$content.$t]]</p>

            <p>[[post.gsx$date.$t]]</p>

            <small>Keywords: [[post.gsx$keywords.$t]]</small>

            </template>

        </div>

    </template>

    <script>

    Polymer('post-element', {

        created: function() { },

        enteredView: function() { },

        leftView: function() { },

        attributeChanged: function(attrName, oldVal, newVal) { }

    });

    </script>

</polymer-element>

Давайте посмотрим, что это нам дает:

Приложение Polymer с пользовательскими элементами

Красивый!

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

Оптимизация вашего приложения

Рабочий процесс Yeoman включает в себя еще один проект с открытым исходным кодом под названием Grunt — средство запуска задач, которое может запускать ряд задач, специфичных для сборки (определенных в Gruntfile), для создания оптимизированной версии вашего приложения. Запуск grunt сам по себе выполнит задачу default , которую генератор настроил для анализа, тестирования и сборки:

grunt.registerTask('default', [

    'jshint',

    'test',

    'build'

]);

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

test задача выглядит примерно так и может создавать и обслуживать ваше приложение для рекомендуемой нами тестовой среды Mocha. Он также выполнит ваши тесты за вас:

grunt.registerTask('test', [

    'clean:server',

    'createDefaultTemplate',

    'jst',

    'compass',

    'connect:test',

    'mocha'

]);

Поскольку наше приложение в данном случае довольно упрощенное, мы оставим написание тестов вам в качестве отдельного упражнения. Есть еще несколько вещей, которые нам понадобятся для дескриптора процесса сборки, поэтому давайте посмотрим, что будет делать задача grunt build , определенная в нашем Gruntfile.js :

grunt.registerTask('build', [

    'clean:dist',    // Clears out your .tmp/ and dist/ folders

    'compass:dist',  // Compiles your Sassiness

    'useminPrepare', // Looks for <!-- special blocks --> in your HTML

    'imagemin',      // Optimizes your images!

    'htmlmin',       // Minifies your HTML files

    'concat',        // Task used to concatenate your JS and CSS

    'cssmin',        // Minifies your CSS files

    'uglify',        // Task used to minify your JS

    'copy',          // Copies files from .tmp/ and app/ into dist/

    'usemin'         // Updates the references in your HTML with the new files

]);

Запустите grunt build , и будет создана рабочая версия вашего приложения, готовая к отправке. Давайте попробуем.

Грантовая сборка

Успех!

Если вы застряли, вы можете ознакомиться с предварительно созданной версией полимерного блога https://github.com/addyosmani/polymer-blog .

Что еще у нас есть в наличии?

Веб-компоненты все еще находятся в состоянии эволюции, как и инструменты вокруг них.

В настоящее время мы рассматриваем, как можно объединить импорт HTML для повышения производительности загрузки с помощью таких проектов, как Vulcanize (инструмент проекта Polymer), и как экосистема компонентов может работать с менеджером пакетов, таким как Bower.

Мы сообщим вам, когда и когда у нас появятся более точные ответы на эти вопросы, но впереди нас ждет много интересных моментов.

Автономная установка Polymer с Bower

Если вы предпочитаете более легкий запуск Polymer, вы можете установить его отдельно непосредственно из Bower, запустив:

bower install polymer

который добавит его в ваш каталог Bower_comComponents. Затем вы можете вручную ссылаться на него в индексе своего приложения и рассчитывать на будущее.

Что вы думаете?

Теперь вы знаете, как создать приложение Polymer с помощью веб-компонентов с Yeoman. Если у вас есть отзывы о генераторе, сообщите нам об этом в комментариях, сообщите об ошибке или опубликуйте сообщение в системе отслеживания проблем Yeoman. Мы хотели бы знать, есть ли что-то еще, что вы хотели бы улучшить в генераторе, поскольку только благодаря вашему использованию и отзывам мы можем улучшить :)