ES2015

ES2015 (precedentemente noto come ES6) è un fantastico passo avanti per il linguaggio JavaScript. Offre nuove funzionalità e un sugaring per i pattern che hanno richiesto un boilerplate significativo in ES5. Sono incluse classi, funzioni a freccia e moduli. In questa puntata parleremo degli strumenti che utilizziamo per sfruttare appieno ES2015 durante la creazione di app web JavaScript.

Trapilazione con Babele

Anche se i motori JavaScript stanno facendo grandi progressi nell'implementazione nativa delle funzionalità di ES2015, c'è un problema. Per utilizzare oggi l'insieme completo delle funzionalità, dovrai ritrasmettere il codice a ES5 in modo che possa essere interpretato dai browser attuali. Fortunatamente, esistono strumenti come Babel che rendono questo processo quasi indolore.

Utilizzo di Babel nel processo di creazione

Babel ti consente di prendere JavaScript scritto utilizzando le caratteristiche ES2015 e di traspilo di nuovo in ES5 in modo che possa funzionare nei browser che oggi non supportano queste funzionalità. L'aggiunta di Babel al processo di creazione può essere eseguita in questo modo.

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'));
});

L'unica funzionalità che Babel non può transpile è rappresentata dai moduli. I moduli ES6 consentono di creare classi ed esportare / importare tra i file. Per transpile i moduli, passa il codice JavaScript tramite Browserify, che unisce i file e poi lo trasmette tramite Babelify (una versione di Babel in grado di gestire l'output da 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/'));
});

Più file JavaScript

L'esempio precedente richiede la definizione di un file specifico, che potrebbe diventare un po' gravoso. Matt esegue le operazioni seguenti in Gulp per cercare ed eseguire il transpile dei file che terminano con .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();
});

Linting e controlli di stile

Esistono poche opzioni per individuare il codice tramite lint per individuare possibili problemi e la conformità dello stile.

JSHint e JSCS

JSHint e JSCS sono gli strumenti più comuni utilizzati per il controllo degli stili JavaScript di oggi.

JSHint evidenzierà eventuali problemi possibili nel codice e richiamerà eventuali pattern generalmente considerati come prassi scorrette.

JSCS esaminerà lo stile del codice, incluso assicurarsi che vengano utilizzate solo tabulazioni o spazi e che gli spazi siano inseriti in punti coerenti.

Per utilizzare JSHint e JSCS sul codice ES2015 devi aggiungere "esnext": true ai tuoi file .jshintrc e .jscsrc

ESLint

ESLint è un linter e un controllo stile alternativi in uno. Questo strumento sta prendendo molto piede e presenta alcune utili funzionalità rispetto a JSHint, ad esempio la possibilità di indicare gli ambienti per cui è stato scritto JavaScript e l'impostazione del livello di errore / avviso per problemi specifici.

ESLint è completamente personalizzabile e fornisce regole di analisi tramite lint personalizzate che ti consentono di disattivare o ridurre le opzioni mediante i file di configurazione. Inoltre, se utilizzi React, ESLint funziona anche con JSX.

Anche la configurazione di ESLint nel processo di compilazione non è troppo complessa.

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...
});

Il team di Babel gestisce babel-estlint, uno strumento che consente di lint qualsiasi codice Babel valido utilizzando ESLint. Sebbene ESLint supporti i parser personalizzati, parte della sintassi supportata da Babel non è supportata direttamente da ESLint, quindi è un'altra opzione se hai bisogno di ulteriore flessibilità. Questa opzione può essere configurata personalizzando la sezione parser del file .eslintrc:

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

Dan Abramov ha scritto un ottimo testo sulla configurazione di ESLint e babel-eslint in Lint Like It's 2015. Spiega inoltre come integrare SublimeLinter-eslint nel flusso di lavoro per il supporto del lint ES2015 in Sublime Text.

Quale servizio dovresti usare? Provali e continua a scegliere quello che funziona meglio per te.

Evidenziazione della sintassi ES2015

Ovviamente vorrai mettere in evidenza la sintassi del codice ES2015. Ci piiamo di usare babel-sublime, che può essere installato da Package Control. Durante la configurazione, ti consigliamo di impostarla come predefinita per tutti i file su cui devi eseguire l'evidenziazione. Questo include ovviamente JS, ma potrebbe riguardare anche JSX se usi React.

Documentare ES2015

Storicamente ci siamo affidati a JSDoc per documentare il nostro codice JavaScript. Sfortunatamente, presenta problemi aperti per il supporto di ES2015 (dovrebbe essere risolto in JSDoc 3), ma ci sono sempre più alternative disponibili mentre siamo in attesa che si mettano al passo. ESDoc è un'opzione di questo tipo e Jonathan Creamer ha scritto una recente scrittura che vale la pena leggere.

Creazione dei file Gulp.js con Babel

Se utilizzi Gulp per il processo di compilazione, ora puoi creare Gulpfile utilizzando qualsiasi sintassi supportata da Babel. Questa operazione viene eseguita nel Web Starter Kit ed è relativamente banale da configurare. Utilizzando una versione recente di Gulp e l'interfaccia a riga di comando Gulp, è sufficiente rinominare il tuo gulpfile.js in gulpfile.babel.js e Gulp interpreterà e trasformerà il tuo gulpfile ES2015 utilizzando Babel automaticamente.

Funzionalità ES2015 preferite

Moduli

I moduli consentono di esportare valori, funzioni e classi da un file, in modo da importarli in un altro file.

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?');
  }
}

Questo sito contiene alcuni ottimi esempi e spiegazioni dei Moduli.

Stringhe del modello

Le stringhe del modello consentono di sostituire la porta di una stringa con una variabile.

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

// => "Yo, Brendan!"

L'aspetto interessante delle stringhe del modello è che la sostituzione è un'esecuzione JavaScript, il che significa che puoi utilizzare funzioni o espressioni incorporate.

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.

Scopri di più in questo pratico post del blog di Addy.

Valori letterali degli oggetti in forma abbreviata

I valori letterali degli oggetti consentono di evitare di definire la chiave e il valore durante la creazione di un oggetto, se la variabile ha lo stesso nome della chiave che vuoi che abbia l'oggetto.

Significato:

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

Diventa questo:

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

Nomi proprietà calcolate

Questa funzionalità in ES2015 consente di creare nomi di proprietà in modo dinamico su un oggetto. I documenti di Mozilla sono un'ottima fonte di informazioni e hanno questo ottimo esempio.

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

Funzioni freccia grassa

Le funzioni a freccia grassa consentono di scrivere funzioni in forma abbreviata, dove:

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

Diventa questo:

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

Oltre ad avere una sintassi più breve, una grande caratteristica dell'uso delle funzioni freccia grassa è che l'ambito dell'oggetto è lo stesso dell'istruzione che li contiene. Ciò significa che non devi chiamare .bind(this) sulla funzione o creare una variabile che = questo.

Ci sono molti altri esempi sulla MDN.

Repository ES6 Tools di Addy

Addy si è impegnata a creare un elenco degli strumenti ES2015 e se gli strumenti qui sopra non fanno al caso tuo, forse utilizzi Grunt invece di Gulp, questa potrebbe essere la risposta giusta per te.

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

Quanto riportato sopra include anche i link a ulteriori strumenti di Babel che possono aiutarti durante il test delle unità e non solo.

Libri da leggere

Esistono due libri che puoi consultare senza costi online per saperne di più su ES2015. Comprendere ECMAScript 6, scritto da Nicholas C. Zakas ed Exploring ES6 scritti dal dottor Axel Rauschmayer.

Torre di Babele

Se ti interessa imparare le funzionalità ES2015 nella riga di comando, tower-of-babel offre una serie di esercizi che potrebbero interessarti. Tutti spiegano come usare Babel.

Altre risorse utili: