ES2015

ES2015 (wcześniej ES6) to wielki krok naprzód w przypadku języka JavaScript. Oferuje nowe funkcje i cukierek pod kątem wzorców, które w ES5 wymagają znacznego powtórzenia. Obejmuje to klasy, funkcje strzałek i moduły. W tym odcinku omówimy narzędzia służące do pełnego wykorzystania standardu ES2015 podczas tworzenia aplikacji internetowych w języku JavaScript.

Transpilacja z użyciem Babel

Mechanizmy JavaScriptu robią wielki postęp w natywnym wdrażaniu funkcji ES2015, ale jest to prawda. Aby korzystać ze wszystkich funkcji już dziś, musisz przetranspilować swój kod z powrotem do wersji ES5. Wtedy będzie można go interpretować w bieżących przeglądarkach. Na szczęście istnieją narzędzia takie jak Babel, dzięki którym ten proces jest bardzo łatwy.

Wykorzystanie Babel w procesie tworzenia

Babel umożliwia wykorzystanie kodu JavaScript napisanego za pomocą funkcji ES2015 i transpilację go z powrotem do ES5, dzięki czemu będzie on działać w przeglądarkach, które obecnie nie obsługują tych funkcji. Dodawanie Babel do procesu tworzenia można zrobić w taki sposób.

var gulp = require('gulp');
var babel = require('gulp-babel');

gulp.task('default', function () {
    return gulp.src('src/app.js')
        .pipe(babel())
        .pipe(gulp.dest('dist'));
});

Jedyną funkcją, której Babel nie może przetranspilować, są moduły. Moduły w ES6 umożliwiają tworzenie zajęć oraz eksportowanie i importowanie klas między plikami. Aby transpilować moduły, przekaż kod JavaScript przez funkcję Browserify, która scala pliki, a następnie do usługi Babelify (wersji Babel, która obsługuje dane wyjściowe z Browserify).

var babelify = require('babelify');
var source = require('vinyl-source-stream');
var browserify = require('browserify');

gulp.task('babelify', function() {
  browserify({ entries: './src.js', debug: true })
    .transform(babelify)
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('./dist/js/'));
});

Wiele plików JavaScript

Powyższy przykład wymaga zdefiniowania konkretnego pliku, co może być uciążliwe. Matt wykonuje w Gulp te czynności, aby wyszukiwać i transpilować pliki z rozszerzeniem .es6.js.

var config = {
  src: 'src/scripts',
  dest: 'dist/scripts'
};
var es6FileGlob = '/**/*.es6.js';

var gulp = require('gulp');
var plugins = require('gulp-load-plugins')();
var glob = require('glob');
var path = require('path');
var browserify = require('browserify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');

// Takes an array of bundles to run through browserify and babelify
function transpileES6Modules(browserifyFileEntries) {
  browserifyFileEntries.forEach(function(fileEntry) {
    var browserifyBundle = browserify({
        entries: [fileEntry.srcPath]
      })
      .transform(babelify);

    var finalStream = browserifyBundle.bundle()
      .on('log', plugins.util.log.bind(plugins.util, 'Browserify Log'))
      .on('error', plugins.util.log.bind(plugins.util, 'Browserify Error'))
      .pipe(source(fileEntry.outputFilename));

    return finalStream.pipe(gulp.dest(fileEntry.dest));
  });
}

// This takes a source path and finds all files ending
// with .es6.js and creates the bundles to run through browserify
// and babelify
function handleES6Scripts(srcPath) {
  var browserifyFileEntries = [];

  var es6Filepaths = glob.sync(srcPath + es6FileGlob);
  es6Filepaths.forEach(function(filepath) {
    var filename = path.basename(filepath);
    var directoryOfFile = path.dirname(filepath);
    var relativeDirectory = path.relative(
      srcPath,
      directoryOfFile);

    // Create an object and add to the browserify bundle array
    browserifyFileEntries.push({
      srcPath: './' + filepath,
      outputFilename: filename,
      dest: path.join(config.dest, relativeDirectory)
    });
  });

  transpileES6Modules(browserifyFileEntries);
}

gulp.task('scripts:es6', ['scripts:lint'], function(cb) {
  handleES6Scripts(config.src);

  cb();
});

Kontrola lintowania i stylu

Podczas lintowania kodu pod kątem potencjalnych problemów i zgodności stylów jest kilka opcji.

JSHint i JSCS

JSHint i JSCS to najpopularniejsze narzędzia używane obecnie do sprawdzania stylów JavaScriptu.

JSHint wskaże możliwe problemy w kodzie oraz wzorce uznawane za nieprawidłowe.

JSCS przeanalizuje styl kodu, m.in. upewniając się, że użyto tylko tabulatorów lub spacji, a spacje należy umieścić w spójnych miejscach.

Aby używać JSHint i JSCS w kodzie ES2015, musisz dodać "esnext": true do plików .jshintrc i .jscsrc

ESLint

ESLint to alternatywny linter i narzędzie do sprawdzania stylów w jednym. To narzędzie wyłapuje sporo paru i ma kilka przydatnych funkcji zamiast JSHint, takich jak wskazywanie środowisk, w których został napisany JavaScript, oraz ustawianie poziomu błędu / ostrzeżenia dla konkretnych problemów.

ESLint można w pełni dostosować i udostępnia niestandardowe reguły lintowania, za pomocą których użytkownik samodzielnie decyduje, czy opcje można wyłączyć czy ograniczyć za pomocą plików konfiguracji. Jeśli używasz React, ESLint działa też z JSX.

Skonfigurowanie ESLint w procesie kompilacji też nie jest zbyt trudne.

var gulp = require('gulp'),
    eslint = require('gulp-eslint');

gulp.task('lint', function () {
    return gulp.src(['js/**/*.js'])
        // eslint() attaches the lint output to the eslint property
        // of the file object so it can be used by other modules.
        .pipe(eslint())
        // eslint.format() outputs the lint results to the console.
        // Alternatively use eslint.formatEach() (see Docs).
        .pipe(eslint.format())
        // To have the process exit with an error code (1) on
        // lint error, return the stream and pipe to failOnError last.
        .pipe(eslint.failOnError());
});

gulp.task('default', ['lint'], function () {
    // This will only run if the lint task is successful...
});

Zespół Babel obsługuje narzędzie babel-estlint, które umożliwia lintowanie za pomocą ESLint dowolnego prawidłowego kodu Babel. Chociaż ESLint obsługuje niestandardowe parsery, część składni obsługiwanej przez Babel nie jest bezpośrednio obsługiwana przez ESLint, dlatego jest to kolejna opcja, jeśli potrzebujesz jeszcze większej elastyczności. Możesz to skonfigurować, dostosowując sekcję parser w pliku .eslintrc:

{
  "parser": "babel-eslint",
  "rules": {
    "strict": 0
  }
}

Dan Abramov ma świetny artykuł na temat konfiguracji ESLint i babel-eslint w serii Lint Like It's 2015. Omówiono w nim również, jak zintegrować SublimeLinter-eslint z obsługą lintowania ES2015 w Sublime Text.

Której usługi użyjesz? Wypróbuj je i trzymaj się tych, które sprawdzają się najlepiej w Twoim przypadku.

Wyróżnianie składni ES2015

Musisz oczywiście zadbać o poprawną składnię kodu ES2015. Cieszymy się z korzystania z programu babel-sublime, który można zainstalować z poziomu kontroli pakietów. Zalecamy, aby podczas konfigurowania ustawić ten tryb jako domyślny dla wszystkich plików, na których ma działać podświetlenie. Oczywiście obejmuje to JSX, ale może też obejmować JSX, jeśli używasz React.

Dokumentowanie ES2015

W przeszłości w dużej mierze polegaliśmy na dokumencie JSDoc do dokumentowania naszego kodu JavaScript. Niestety w przypadku ES2015 występują otwarte problemy z obsługą ES2015 (które należy rozwiązać w JSDoc 3), jednak do tego czasu dostępnych jest coraz więcej innych rozwiązań. Jednym z takich rozwiązań jest ESDoc – Jonathan Creamer przygotował niedawno recenzję na ten temat.

Tworzenie plików Gulp.js przy użyciu Babel

Jeśli używasz Gulp w procesie kompilacji, możesz teraz tworzyć Gulpfiles, korzystając z dowolnej składni obsługiwanej przez Babel. Robimy to w Web Starter Kit, a jego konfiguracja jest stosunkowo prosta. Korzystając z najnowszej wersji interfejsu Gulp i interfejsu wiersza poleceń Gulp, po prostu zmień nazwę gulpfile.js na gulpfile.babel.js, a Gulp automatycznie zinterpretuje i przetranspiluje plik ES2015 za pomocą Babel.

Ulubione funkcje ES2015

Moduły

Moduły to sposób na eksportowanie wartości, funkcji i klas z jednego pliku, umożliwiając ich zaimportowanie do innego pliku.

export function exampleFunction() {
  console.log('I\'m an example. #TrueStory');
}



import { exampleFunction } from './example-function';
import BaseController from './base-controller';

export default class ExampleController extends BaseController {
  constructor() {
    super();

    exampleFunction();
  }

  doSomething() {
    console.log('What should I do? Change the DOM? Print a dancing shark to the console?');
  }
}

W tej witrynie znajdziesz świetne przykłady i objaśnienia modułów.

Ciągi tekstowe szablonów

Ciągi tekstowe szablonu umożliwiają zastąpienie portu ciągu znaków zmienną.

// Simple string substitution
var name = "Brendan";
console.log('Yo, ${name}!');

// => "Yo, Brendan!"

Zaletą ciągów w szablonie jest to, że zastąpienie to wykonanie kodu JavaScript, co oznacza, że możesz używać funkcji lub wyrażeń w tekście.

var a = 10;
var b = 10;
console.log('a+b = ${a+b}.');
//=> a+b = 20.

function fn() { return "I am a result. Rarr"; }
console.log('foo ${fn()} bar');
//=> foo I am a result. Rarr bar.

Więcej informacji znajdziesz w tym poście na blogu autorstwa Addy'ego.

Literały obiektów skrótowe

Litery obiektów pozwalają uniknąć definiowania klucza i wartości podczas tworzenia obiektu, jeśli zmienna ma taką samą nazwę jak klucz, który chcesz mieć obiekt.

Czyli:

function createObject(name, data) {
  return { name: name, data: data };
}

Zmieni się w:

function createObject(name, data) {
  return { name, data };
}

Obliczone nazwy właściwości

Ta funkcja w ES2015 umożliwia dynamiczne tworzenie nazw właściwości w obiekcie. Dokumenty Mozilla są świetnym źródłem informacji i mają doskonały przykład.

var a = {
  ["foo" + ++i]: i,
  ["foo" + ++i]: i,
  ["foo" + ++i]: i
};

console.log(a.foo1); // 1
console.log(a.foo2); // 2
console.log(a.foo3); // 3

Funkcje strzałek tkanki tłuszczowej

Funkcje grubych strzałek pozwalają pisać funkcje w skrócie, gdzie:

button.addEventListener('click', function(event) {
  console.log('The button has received a click', event);
});

Zmieni się w:

button.addEventListener('click', (event) => {
  console.log('The button has received a click', event);
});

Oprócz krótszej składni jedną z ważnych funkcji stosowania funkcji grubej strzałki jest to, że zakres obiektu jest taki sam jak instrukcja zamykająca. Oznacza to, że nie musisz wywoływać ciągu .bind(this) w swojej funkcji ani tworzyć zmiennej = to.

Znacznie więcej przykładów można znaleźć w MDN.

Repozytorium Addy's ES6 Tools Tools

Addy poświęciła czas na prowadzenie listy narzędzi ES2015. Jeśli podane wyżej narzędzia Ci nie odpowiadają, być może używasz Grunt zamiast Gulp? W takim razie może znajdziesz odpowiedź.

https://github.com/addyosmani/es6-tools

Powyżej znajdziesz też linki do dodatkowych narzędzi Babel, które mogą być przydatne podczas testowania jednostkowego i nie tylko.

Książki warte przeczytania

Aby dowiedzieć się więcej o ES2015, są dwie książki, które możesz bezpłatnie kupić online. Zrozumienie ECMAScript 6 napisane przez Nicholasa C. Zakas i Exploring ES6: dr Axel Rauschmayer.

Wieża Babel

Jeśli chcesz poznać funkcje ES2015 w wierszu poleceń, zapoznaj się z serią ćwiczeń tower-of-babel. Każda z nich skorzysta z Babela.

Inne materiały, które mogą Cię zainteresować: