ES6 bez tajemnic. Korzystanie z ES6 z pomocą narzędzi Babel i Broccoli

15 grudnia 2015
1 gwiadka2 gwiazdki3 gwiazdki4 gwiazdki5 gwiazdek

ES6 bez tajemnic to cykl artykułów poświęconych nowym składnikom języka JavaScript, które pojawiły się w 6. edycji standardu ECMAScript, w skrócie ES6.

Standard ES6 niedawno został oficjalnie zatwierdzony, a już mówi się o wersji ES7. O tym, co przyniesie przyszłość i jakich nowych elementów funkcjonalności można spodziewać się w nowym standardzie. My, programiści stron internetowych, zastanawiamy się natomiast jak będziemy je mogli wykorzystać. W poprzednich artykułach z serii ES6 bez tajemnic kilkakrotnie zachęcaliśmy cię, drogi czytelniku, byś zaczął pisać swój kod w standardzie ES6 z niewielką pomocą kilku interesujących narzędzi. Droczyliśmy się z tobą, mówiąc, że masz taką możliwość:

Jeśli chciałbyś skorzystać z nowej składni w kodzie przeglądarkowym, możesz użyć kompilatora Babel lub Traceur firmy Google, który przetłumaczy kod w standardzie ES6 na przyjazny przeglądarkom ES5.

Dziś pokażemy ci jak tego dokonać krok po kroku. Wymienione powyżej narzędzia to tak zwane transpilatory. Transpilator znany jest również jako kompilator ze źródła do źródła (ang. source-to-source compiler), czyli program tłumaczący pomiędzy językami programowania operującymi na podobnym poziomie abstrakcji. Transpilatory umożliwiają pisanie kodu w standardzie ES6, jednocześnie gwarantując, że będzie on wykonywalny w każdej przeglądarce.

Transpilacja naszym wybawieniem

Korzystanie z transpilatora jest bardzo proste. Jego działanie można opisać w zaledwie dwóch krokach:

  1. Piszemy kod zgodnie ze składnią ES6.
    let q = 99;
    let myVariable = `${q} bottles of beer on the wall, ${q} bottles of beer.`;
    
  2. Używamy powyższego kodu jako danych wejściowych transpilatora, który następnie go przetwarza i otrzymujemy następujący wynik:
    "use strict";
    
    var q = 99;
    var myVariable = "" + q + " bottles of beer on the wall, " + q + " bottles of beer."
    

To stary, dobry kod JavaScript, do którego zdążyliśmy przywyknąć. Można z niego korzystać w dowolnej przeglądarce.

Poszczególne operacje wykonywane przez transpilator w celu przetworzenia danych wejściowych na dane wynikowe są wysoce skomplikowane i wykraczają poza zakres niniejszego artykułu. Tak jak możemy prowadzić samochód bez znajomości szczegółów pracy silnika, tak też możemy na tę chwilę potraktować transpilator jak czarną skrzynkę przetwarzającą nasz kod.

Babel w akcji

Kompilatora Babel możemy użyć w pracy nad projektem na kilka sposobów. Zawiera on na przykład wiersz poleceń, w którym można wykonać polecenia typu:

babel script.js --out-file script-compiled.js

Wersja przeglądarkowa jest również dostępna. Ponadto możemy wykorzystać Babel jako zwykłą bibliotekę JS – wówczas kod ES6 umieszczamy w znacznikach script z typem „text/babel”.

<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel">
// twój kod ES6
</script>

Metody te nie są jednak skalowalne, gdy kod bazowy zaczyna się rozrastać i zaczynamy dzielić wszystko na wiele plików i folderów. Wówczas trzeba zaopatrzyć się w narzędzie do automatyzowania kompilacji i wkomponować w cały ten proces bibliotekę Babel.

Pokażę teraz, jak zintegrować Babel z narzędziem do automatyzowania kompilacji Broccoli.js. Napiszemy i wykonamy pierwsze linijki kodu ES6 z pomocą dwóch przykładów. W razie kłopotów możesz przejrzeć kod źródłowy, dostępny w całości tutaj: broccoli-babel-examples. W repozytorium znajdują się trzy przykładowe projekty:

  1. es6-fruits
  2. es6-website
  3. es6-modules

Każdy z nich bazuje na swoim poprzedniku. Zaczynamy od absolutnych podstaw, by przejść do ogólnego rozwiązania, które można zastosować jako punkt wyjścia do ambitnego projektu. W tym artykule omówimy szczegółowo dwa pierwsze przykłady. Później będziesz już gotowy samodzielnie przeczytać i zrozumieć kod źródłowy z trzeciego przykładu.

Jeśli myślisz sobie, że możesz poczekać aż przeglądarki zaczną same obsługiwać nowe elementy JS, to zostaniesz w tyle. Osiągnięcie pełnej zgodności, o ile w ogóle to nastąpi, zajmie dużo czasu. Transpilatory będą nam potrzebne – nowe wersje ECMAScriptu mają być wydawane co roku. Oznacza to, że nowe standardy będą w dalszym ciągu pojawiać się częściej niż jednolite platformy przeglądarkowe. Dołącz więc teraz do nas i skorzystaj z nowych składników JS.

Nasz pierwszy projekt z użyciem narzędzi Broccoli i Babel

Broccoli to narzędzie mające kompilować projekty tak szybko jak to możliwe. Korzystając z wtyczek Broccoli możemy, między innymi, poddać pliki minifikacji bądź obrzydzaniu (ang. uglify). Broccoli wyręcza nas w obsłudze plików, katalogów i wywoływaniu poleceń wraz z każdą wprowadzoną w projekcie zmianą. Można powiedzieć, że to narzędzie:

Konfiguracja projektu

Środowisko Node

Jak zapewne się domyślasz, musisz zainstalować środowisko Node w wersji 0.11 lub nowszej.

Jeśli jesteś użytkownikiem systemu uniksowego, postaraj się nie instalować Node poprzez system zarządzania pakietami (apt, yum). Chodzi o to, by podczas instalacji uniknąć korzystania z uprawnień root. Najlepiej ręcznie zainstalować znajdujące się pod podanym odnośnikiem pliki binarne z aktualnie używanego konta użytkownika. Aby dowiedzieć się dlaczego korzystanie z użytkownika root nie jest rekomendowane, przeczytaj artykuł Do not sudo npm. Znajdziesz tam opisy innych sposobów instalacji.

Broccoli

Na początek przeprowadzimy konfigurację projektu Broccoli:

mkdir es6-fruits
cd es6-fruits
npm init
# utwórz pusty plik o nazwie Brocfile.js
touch Brocfile.js

Teraz zainstalujemy bibliotekę broccoli i narzędzie broccoli-cli.

# biblioteka broccoli
npm install --save-dev broccoli
# wiersz poleceń
npm install -g broccoli-cli

Napiszmy coś w ES6

Utworzymy folder src i umieścimy w nim plik fruits.js.

mkdir src
vim src/fruits.js

W naszym nowym pliku zapiszemy krótki skrypt z wykorzystaniem składni ES6.

let fruits = [
  {id: 100, name: 'strawberry'},
  {id: 101, name: 'grapefruit'},
  {id: 102, name: 'plum'}
];

for (let fruit of fruits) {
  let message = `ID: ${fruit.id} Name: ${fruit.name}`;

  console.log(message);
}

console.log(`List total: ${fruits.length}`);

Powyższy przykładowy kod wykorzystuje trzy składniki ES6:

  1. słowo kluczowe let do deklaracji o lokalnym zakresie (będzie ono tematem jednego z kolejnych artykułów);
  2. pętle for-of;
  3. łańcuchy szablonowe.

Zapisz plik i spróbuj go wykonać.

node src/fruits.js

Plik ten na razie nie zadziała, ale już za chwilę sprawimy, że będzie wykonywalny w środowisku Node i dowolnej przeglądarce.

let fruits = [
    ^^^^^^
SyntaxError: Unexpected identifier

Pora na transpilację

Teraz za pomocą Broccoli wczytamy nasz kod i skompilujemy go w narzędziu Babel. Dokonamy edycji pliku Brocfile.js, dodając do niego poniższy kod:

// zaimportuj wtyczkę Babel
var babel = require('broccoli-babel-transpiler');

// pobierz kod źródłowy i wykonaj jego transpilację w 1 kroku
fruits = babel('src'); // src/*.js

module.exports = fruits;

Zwróć uwagę, że potrzebujemy wtyczki Broccoli o nazwie broccoli-babel-transpiler, która rozszerza bibliotekę Babel. Musimy ją zatem zainstalować w taki sposób:

npm install --save-dev broccoli-babel-transpiler

Teraz możemy skompilować nasz projekt i wykonać skrypt:

broccoli build dist # kompilacja
node dist/fruits.js # wykonanie kodu ES5

Powinniśmy otrzymać następujący wynik:

ID: 100 Name: strawberry
ID: 101 Name: grapefruit
ID: 102 Name: plum
List total: 3

To było proste! Możesz otworzyć plik dist/fruits.js, by zobaczyć jak wygląda kod po transpilacji. Fajną właściwością transpilatora Babel jest to, że generuje on czytelny kod.

Pisanie kodu ES6 pod kątem stron internetowych

Zagadnienie to poruszymy w naszym drugim przykładzie. Na początek wyjdź z folderu es6-fruits i utwórz katalog es6-website, postępując zgodnie z krokami opisanymi powyżej, w części Konfiguracja projektu.

W folderze src utworzymy trzy pliki:

src/index.html

<!DOCTYPE html>
<html>
  <head>
    <title>ES6 Today</title>
  </head>
  <style>
    body {
      border: 2px solid #9a9a9a;
      border-radius: 10px;
      padding: 6px;
      font-family: monospace;
      text-align: center;
    }
    .color {
      padding: 1rem;
      color: #fff;
    }
  </style>
  <body>
    <h1>ES6 Today</h1>
    <div id="info"></div>
    <hr>
    <div id="content"></div>

    <script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
    <script src="js/my-app.js"></script>
  </body>
</html>

src/print-info.js

function printInfo() {
  $('#info')
  .append('<p>minimal website example with' +
          'Broccoli and Babel</p>');
}

$(printInfo);
src/print-colors.js
// generator ES6
function* hexRange(start, stop, step) {
  for (var i = start; i < stop; i += step) {
    yield i;
  }
}

function printColors() {
  var content$ = $('#content');

  // wymyślony przykład
  for ( var hex of hexRange(900, 999, 10) ) {
    var newDiv = $('<div>')
      .attr('class', 'color')
      .css({ 'background-color': `#${hex}` })
      .append(`hex code: #${hex}`);
    content$.append(newDiv);
  }
}

$(printColors);

Być może zauważyłeś ten fragment: function* hexRange – tak, to generator ES6. Na tę chwilę nie jest to jednak element funkcjonalności obsługiwany we wszystkich przeglądarkach. Aby z niego skorzystać, będziemy potrzebować wypełniacza, dostępnego w narzędziu Babel. Użyjemy go już wkrótce.

Następnym krokiem jest scalenie wszystkich plików JS i wykorzystanie ich na stronie internetowej. Najtrudniej będzie napisać plik Brocfile. Tym razem zainstalujemy 4 wtyczki:

npm install --save-dev broccoli-babel-transpiler
npm install --save-dev broccoli-funnel
npm install --save-dev broccoli-concat
npm install --save-dev broccoli-merge-trees

Wykorzystajmy je praktyce:

// transpilator Babel
var babel = require('broccoli-babel-transpiler');
// drzewa filtrów (podzbiory plików)
var funnel = require('broccoli-funnel');
// połącz drzewa
var concat = require('broccoli-concat');
// scal drzewa
var mergeTrees = require('broccoli-merge-trees');

// dokonaj transpilacji plików źródłowych
var appJs = babel('src');

// pobierz plik wypełniacza z biblioteki Babel
var babelPath = require.resolve('broccoli-babel-transpiler');
babelPath = babelPath.replace(/\/index.js$/, '');
babelPath += '/node_modules/babel-core';
var browserPolyfill = funnel(babelPath, {
  files: ['browser-polyfill.js']
});

// dodaj wypełniacz Babel do drzewa stranspilowanych plików
appJs = mergeTrees([browserPolyfill, appJs]);

// połącz wszystkie pliki JS w jeden plik
appJs = concat(appJs, {
  // określamy porządek łączenia
  inputFiles: ['browser-polyfill.js', '**/*.js'],
  outputFile: '/js/my-app.js'
});

// pobierz plik index
var index = funnel('src', {files: ['index.html']});

// pobierz wszystkie drzewa
// i wyeksportuj je jako pojedyncze, ostateczne drzewo
module.exports = mergeTrees([index, appJs]);

Czas skompilować i wykonać nasz kod.

broccoli build dist

Tym razem w folderze dist powinieneś zobaczyć następującą strukturę:

$> tree dist/
dist/
├── index.html
└── js
    └── my-app.js

To statyczna strona internetowa, której działanie możesz sprawdzić na dowolnym serwerze. Przykład:

cd dist/
python -m SimpleHTTPServer
# odwiedź http://localhost:8000/

Powinno wyświetlić się to:

Przykładowy zrzut ekranu

Więcej zabawy z narzędziami Babel i Broccoli

Drugi przykład pokazuje, jak wiele można osiągnąć korzystając z transpilatora Babel. Na jakiś czas powinno ci to wystarczyć. Jeśli chciałbyś natomiast w większym stopniu wykorzystać ES6, Babel i Broccoli, odwiedź to repozytorium: broccoli-babel-boilerplate. To także konfiguracja oparta na narzędziach Babel i Broccoli, w bardziej zaawansowanej wersji. Obsługuje moduły, importowanie i testowanie jednostkowe.

Przykład jej praktycznego użycia możesz znaleźć tutaj: es6-modules. Cała magia zawarta jest w pliku Brocfile i znacznie przypomina to, co już zdążyliśmy omówić.

Jak widać, dzięki narzędziom Babel i Broccoli można w praktyczny sposób wykorzystać składniki ES6 na stronach internetowych już dziś. Podziękowania dla Gastóna I. Silvy za niniejszy artykuł!

Omówiliśmy już wiele tematów, ale wciąż czeka na nas jeszcze kilka najpotężniejszych składników ES6. Odwiedzaj nas zatem regularnie, by nie przegapić kolejnego artykułu.

Jason Orendorff, Redaktor serii ES6 bez tajemnic

Autor: Gastón I. Silva

Źródło: https://hacks.mozilla.org/2015/06/es6-in-depth-babel-and-broccoli/

Tłumaczenie: Joanna Liana

Treść tej strony dostępna jest na zasadach licencji CC BY-SA 3.0

Zobacz również:

1 komentarz

  1. Witam. W artykule jest błąd. Mianowicie w kodzie źródłowym drugiego pliku ‚print-info.js’ zawarte są dwa pliki (print-info.js oraz print-color.js).

    function printInfo() {
    $(‚#info’)
    .append(‚minimal website example with’ +
    ‚Broccoli and Babel’);
    }

    $(printInfo);

    // ——- tutaj powinno być zakończenie pierwszego pliku —–

    To jest nazwa drugiego pliku: —–> src/print-colors.js

    // ——- to jest początek drugiego pliku ——–

    // generator ES6
    function* hexRange(start, stop, step) {
    for (var i = start; i < stop; i += step) {
    yield i;
    }

    Odpowiedz

Dyskusja

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *