Tworzenie aplikacji internetowych za pomocą Yeoman i Polymer

Wykorzystanie nowoczesnych narzędzi do tworzenia aplikacji internetowych

Addy Osmani
Addy Osmani

Wstęp

Allo to Allo. Każdy, kto tworzy aplikację internetową, wie, jak ważna jest produktywność. Nie jest to łatwy wybór.

Na szczęście nowoczesne narzędzia frontendu pomagają zautomatyzować większość tych zadań, dzięki czemu możesz skupić się na napisaniu aplikacji błyskawicznej. W tym artykule pokażemy, jak wykorzystać Yeoman – przepływ pracy narzędzi dla aplikacji internetowych do usprawnienia tworzenia aplikacji przy użyciu Polymera – biblioteki polyfill i cukru do tworzenia aplikacji przy użyciu komponentów internetowych.

Yeoman

Poznajcie Yo, Grunta i Bowera

Yeoman to mężczyzna w kapeluszu i korzystający z 3 narzędzi zwiększających produktywność:

  • yo to narzędzie do rusztowania obejmującego ekosystem rusztowań, zwany generatorami, które można wykorzystać do wykonania niektórych żmudnych zadań, o których wspominałem wcześniej.
  • Język grunt służy do tworzenia, podglądu i testowania projektu dzięki zadaniom wyselekcjonowanym przez zespół Yeoman oraz grunt-contrib.
  • bower służy do zarządzania zależnościami, dzięki czemu nie musisz już ręcznie pobierać skryptów ani nimi zarządzać.

Wystarczy 1 lub 2 polecenia, aby napisać stały kod aplikacji (lub jego poszczególne elementy, np. Modele), skompilować skrypt Sass, zminimalizować i połączyć ze sobą pliki CSS, JS, HTML i obrazy oraz uruchomić prosty serwer WWW w bieżącym katalogu. Może też przeprowadzać testy jednostkowe.

Możesz instalować generatory z modułów w pakiecie węzłów (npm). Obecnie dostępnych jest ponad 220 generatorów, z których wiele zostało opracowanych przez społeczność open source. Popularne generatory to między innymi generator-angular, generator-szkielet-generator i generator-ember.

Strona główna Yeoman

Po zainstalowaniu najnowszej wersji Node.js przejdź do najbliższego terminala i uruchom:

$ npm install -g yo

Znakomicie. Masz teraz karty Yo, Grunt i Bower, które można uruchamiać bezpośrednio z poziomu wiersza poleceń. Oto wyniki uruchomienia yo:

Montaż Yeoman

Generator polimerów

Jak już mówiliśmy, Polymer to biblioteka komponentów polyfill i cukru, która umożliwia korzystanie z komponentów sieciowych w nowoczesnych przeglądarkach. Projekt umożliwia programistom tworzenie aplikacji z wykorzystaniem platformy przyszłości i informowanie W3C o miejscach, w których można jeszcze bardziej ulepszyć specyfikacje samolotu.

Strona główna generatora polimerów

generator-polymer to nowy generator, który ułatwia tworzenie i importowanie niestandardowych elementów Polymer za pomocą wiersza poleceń oraz zaimportowanie ich za pomocą funkcji importowania HTML; Dzięki temu oszczędzasz czas, pisząc za Ciebie standardowy kod.

Następnie zainstaluj generator Polymer, uruchamiając polecenie:

$ npm install generator-polymer -g

To wszystko. Twoja aplikacja ma teraz supermoce komponentów sieciowych.

Nasz nowo zainstalowany generator ma kilka konkretnych informacji, do których będziesz mieć dostęp:

  • Element polymer:element służy do tworzenia rusztowania nowych poszczególnych elementów Polymer. Przykład: yo polymer:element carousel
  • polymer:app służy do tworzenia szkieletu początkowego pliku index.html, czyli pliku Gruntfile.js zawierającego konfigurację czasu kompilacji dla projektu, a także zadania Grunt i strukturę folderów zalecane dla projektu. Umożliwi Ci to też korzystanie z modelu Sass Bootstrap w stylach projektu.

Utwórzmy aplikację w Polymer

Utworzymy prostego bloga, korzystając z niestandardowych elementów Polymer i naszego nowego generatora.

Aplikacja Polymer

Na początek przejdź do terminala, utwórz nowy katalog i zapisz go na dysku CD, korzystając z mkdir my-new-project && cd $_. Możesz teraz uruchomić aplikację Polymer, uruchamiając następujące polecenia:

$ yo polymer
Tworzenie aplikacji Polymer

Spowoduje to pobranie najnowszej wersji Polymer od firmy Bower oraz utworzenie index.html, struktury katalogów i zadań Grunt na potrzeby przepływu pracy. Możecie napić się kawy, gdy czekamy na zakończenie przygotowań do aplikacji?

OK, teraz możemy uruchomić grunt server, by wyświetlić podgląd aplikacji:

Serwer Grunt

Serwer obsługuje LiveUpload, co oznacza, że po zapisaniu możesz uruchomić edytor tekstu, zmodyfikować element niestandardowy, a przeglądarka załaduje się ponownie. Pozwala to zobaczyć bieżący stan aplikacji w czasie rzeczywistym.

Teraz utworzymy nowy element Polymer reprezentujący post na blogu.

$ yo polymer:element post
Utwórz element posta

Yeoman zadaje nam kilka pytań, na przykład, czy chcemy zastosować konstruktor, czy użyć importu HTML, aby uwzględnić element posta w elemencie index.html. Powiedzmy „Nie” w przypadku 2 pierwszych opcji, a trzecią pozostaw pustą.

$ 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

W katalogu /elements zostanie utworzony nowy element Polymer o nazwie 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>

Zawiera ona:

Praca z prawdziwym źródłem danych

Nasz blog musi mieć miejsce do pisania i czytania nowych postów. Aby pokazać, jak działa autentyczna usługa danych, użyjemy interfejsu Google Apps Sheets API. Dzięki temu możemy łatwo odczytywać zawartość dowolnego arkusza kalkulacyjnego utworzonego w Dokumentach Google.

Skonfigurujmy te ustawienia:

  1. W przeglądarce (zalecamy użycie Chrome) otwórz ten arkusz kalkulacyjny Dokumentów Google. Zawiera przykładowe dane posta w tych polach:

    • Identyfikator
    • Tytuł
    • Autor
    • treści
    • Data
    • Słowa kluczowe
    • E-mail (autora)
    • Końcówka adresu (adres URL typu końcówki posta)
  2. Otwórz menu Plik i wybierz Utwórz kopię, aby utworzyć własną kopię arkusza kalkulacyjnego. Treści możesz edytować w dowolnym momencie, dodając i usuwając posty.

  3. Ponownie otwórz menu Plik i wybierz Opublikuj w internecie.

  4. Kliknij Rozpocznij publikowanie.

  5. W sekcji Uzyskaj link do opublikowanych danych skopiuj część podanego adresu URL zawierającą klucz z ostatniego pola tekstowego. Wygląda tak: https://docs.google.com/spreadsheet/ccc?key=0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc#gid=0

  6. Wklej klucz w tym adresie URL w miejscu, gdzie znajduje się tekst your-key-goes-here: https://spreadsheets.google.com/feeds/list/your-key-goes-here/od6/public/values?alt=json-in-script&callback=. Przykład z użyciem powyższego klucza może wyglądać tak: https://spreadsheets.google.com/feeds/list/0AhcraNy3sgspdDhuQ2pvN21JVW9NeVA0M1h4eGo3RGc/od6/public/values?alt=json-in-script

  7. Możesz wkleić ten adres URL w przeglądarce i przejść do niego, aby wyświetlić wersję JSON swojego bloga. Zanotuj adres URL, a następnie poświęć chwilę na sprawdzenie formatu danych, ponieważ później trzeba będzie je powtórzyć, aby wyświetlić je na ekranie.

Wynik JSON w przeglądarce może wyglądać nieco zniechęcający, ale bez obaw. Interesują nas tylko dane dotyczące Twoich postów.

Interfejs API Arkuszy Google wstawia dla każdego pola arkusza kalkulacyjnego specjalny prefiks post.gsx$. np. post.gsx$title.$t, post.gsx$author.$t, post.gsx$content.$t i tak dalej. Podczas iteracji z każdym „wierszem” w danych wyjściowych JSON odwołamy się do tych pól, aby uzyskać odpowiednie wartości dla każdego posta.

Możesz teraz edytować nowo utworzony element posta, aby bind fragmenty znaczników z danymi w arkuszu kalkulacyjnym. W tym celu wprowadzamy atrybut post, który będzie odczytywać utworzony wcześniej tytuł, autor, treść i inne pola. Atrybut selected (który uzupełnimy później) jest używany do wyświetlania posta tylko wtedy, gdy użytkownik przejdzie do właściwej dla niego końcówki adresu.

<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>

Teraz utworzymy element bloga zawierający zarówno zbiór postów, jak i układ bloga. W tym celu uruchomimy polecenie 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

Tym razem importujemy bloga do pliku index.html za pomocą importów HTML, który ma być wyświetlany na stronie. W przypadku trzeciego promptu jako element, który chcemy uwzględnić, określamy post.html.

Tak jak wcześniej, tworzony jest nowy plik elementu (blog.html) i dodany do sekcji /elements. Tym razem zaimportujesz post.html i dodasz parametr <post-element> do tagu szablonu:

<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>

Poprosiliśmy o zaimportowanie elementu bloga do naszego indeksu za pomocą importów HTML (to sposób na uwzględnienie i ponowne wykorzystanie dokumentów HTML w innych dokumentach HTML). Możemy też sprawdzić, czy został on prawidłowo dodany do dokumentu <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>

Fantastyczne.

Dodawanie zależności za pomocą Bower

Teraz edytujmy nasz element, aby użyć elementu narzędziowego Polymer JSONP do odczytu w posts.json. Aby pobrać adapter, możesz sklonować repozytorium za pomocą polecenia git lub zainstalować polymer-elements za pomocą Bower, uruchamiając polecenie bower install polymer-elements.

Zależności Bower

Gdy to zrobisz, musisz zaimportować je do elementu blog.html jako import:

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

Następnie dodaj do niego tag i dodaj parametr url do arkusza kalkulacyjnego z postami na blogu (poprzednio), dodając &callback= na końcu:

<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>

Po wprowadzeniu tych zmian możemy teraz dodawać szablony do powtórzenia arkusza kalkulacyjnego, gdy zostanie on już odczytany. W pierwszej kolejności generujemy spis treści z linkiem do tytułu posta wskazującego jego końcówkę.

<!-- 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>

Drugie renderuje 1 wystąpienie post-element dla każdego znalezionego wpisu, przekazując do niego treść posta. Zwróć uwagę, że przechodzimy atrybut post reprezentujący treść posta w jednym wierszu arkusza kalkulacyjnego oraz atrybut selected, który uzupełnimy trasą.

<!-- Post content -->

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

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

</template>

Używany w naszym szablonie atrybut repeat tworzy i utrzymuje wystąpienie z wartością [[ powiązania ]] dla każdego elementu w kolekcji tablicy naszych postów, jeśli jest on podany.

Aplikacja Polymer

Aby obecny parametr [[route]] został wypełniony, użyjemy biblioteki o nazwie Flatiron Director, która przypisuje wartość [[route]] przy każdej zmianie skrótu adresu URL.

Na szczęście jest element Polymer (w pakiecie więcej elementów), który możemy dla niego wykorzystać. Po skopiowaniu do katalogu /elements możemy odwoływać się do niego za pomocą polecenia <flatiron-director route="[[route]]" autoHash></flatiron-director>, określając wartość route jako właściwość, z którą chcesz powiązać, i nakazując jej automatyczne odczytywanie wartości wszystkich zmian skrótu (autoHash).

Po połączeniu wszystkich elementów otrzymujemy:

    <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>
Aplikacja Polymer

Super! Mamy teraz prostego bloga, który odczytuje dane z JSON i używa 2 elementów Polymer powiązanych z Yoomanem.

Praca z elementami innych firm

Ekosystem elementów związanych z komponentami internetowymi stale się rozrasta, a coraz częściej pojawiają się witryny z galeriami komponentów, takie jak customelements.io. Po przejrzeniu elementów utworzonych przez społeczność udało mi się znaleźć narzędzie do pobierania profili Gravatar. Możemy je również wykorzystać i dodać do witryny naszego bloga.

Elementy niestandardowe – strona główna

Skopiuj źródła elementów Gravatar do katalogu /elements, uwzględnij je za pomocą importowanych plików HTML w pliku post.html, a następnie dodaj atrybut do szablonu, przekazując pole e-mail z naszego arkusza kalkulacyjnego jako źródło nazwy użytkownika. Doskonale!

<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>

Przyjrzyjmy się, co to daje:

Aplikacja Polymer z elementami niestandardowymi

Pięknie!

W krótkim czasie stworzyliśmy prostą aplikację złożoną z kilku komponentów sieciowych i nie trzeba przy tym pisać powtarzalnego kodu, ręcznie pobierać zależności, konfigurować lokalny serwer czy przepływ pracy kompilacji.

Optymalizacja aplikacji

Przepływ pracy na platformie Yeoman obejmuje inny projekt open source o nazwie Grunt – narzędzie do uruchamiania zadań, które może uruchamiać wiele zadań specyficznych dla kompilacji (zdefiniowanych w pliku Gruntfile) w celu utworzenia zoptymalizowanej wersji aplikacji. Uruchomienie samodzielnie grunt spowoduje uruchomienie zadania default skonfigurowanego przez generator na potrzeby lintowania, testowania i kompilacji:

grunt.registerTask('default', [

    'jshint',

    'test',

    'build'

]);

Powyższe zadanie jshint sprawdzi połączenie z plikiem .jshintrc, aby poznać Twoje ustawienia, a następnie uruchomi je na wszystkich plikach JavaScript w Twoim projekcie. Pełną listę opcji JSHint znajdziesz w dokumentacji.

Zadanie test wygląda mniej więcej tak jak to. Może ono utworzyć i udostępnić Twoją aplikację na potrzeby platformy testowej, którą polecamy od razu, czyli Mocha. Przeprowadzi też testy za Ciebie:

grunt.registerTask('test', [

    'clean:server',

    'createDefaultTemplate',

    'jst',

    'compass',

    'connect:test',

    'mocha'

]);

Ponieważ aplikacja jest w tym przypadku dość uproszczona, pisanie testów pozostanie dla Ciebie oddzielnym zadaniem. Jest kilka innych rzeczy, które będą potrzebne do obsługi procesu kompilacji. Przyjrzyjmy się działaniu grunt build zdefiniowanemu w 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

]);

Uruchom grunt build. Aplikacja powinna być gotowa do wysyłki. Spróbujmy.

Budynek Grunt

Gotowe.

Jeśli napotkasz problemy, możesz skorzystać z gotowej wersji Polymer-blog na https://github.com/addyosmani/polymer-blog.

Co jeszcze mamy w sklepie?

Komponenty sieciowe są wciąż w stanie ewolucji, dlatego dostępne są powiązane z nimi narzędzia.

Obecnie przyglądamy się możliwościom konkatenacji importów HTML w celu zwiększenia wydajności wczytywania za pomocą projektów takich jak Vulcanize (narzędzie opracowane przez projekt Polymer) oraz możliwości współpracy ekosystemu komponentów z menedżerem pakietów takim jak Bower.

Powiadomimy Cię, gdy będziemy mogli uzyskać lepsze odpowiedzi na te pytania, ale przed Tobą wiele ciekawych czasów.

Instalowanie samodzielnych urządzeń Polymer z Bower

Jeśli wolisz użyć lżejszego kodu Polymer, możesz zainstalować go samodzielnie bezpośrednio z Bower. W tym celu uruchom:

bower install polymer

który doda go do katalogu bower_components. Możesz później samodzielnie uwzględnić je w indeksie aplikacji i zapewnić świetną przyszłość.

Jak myślisz?

Wiesz już, jak przygotować aplikację Polymer za pomocą komponentów Web Komponenty w aplikacji Yeoman. Jeśli chcesz podzielić się opinią na temat generatora, daj nam znać w komentarzach lub zgłoś błąd albo zadaj pytanie w narzędziu Yeoman do śledzenia problemów. Chętnie dowiemy się, czy jest jeszcze coś, co według Ciebie powinniśmy poprawić w generatorze, bo tylko dzięki Twojemu wykorzystaniu i opiniom możemy go ulepszyć :)