O ES2015 (anteriormente ES6) é um avanço fantástico para a linguagem JavaScript. Ela traz novos recursos e aprimoramento para padrões que exigiam código boilerplate significativo no ES5. Isso inclui classes, funções de seta e módulos. Neste episódio, abordamos as ferramentas que usamos para aproveitar ao máximo o ES2015 ao criar apps da Web em JavaScript.
Transpilação com Babel
Embora os mecanismos JavaScript estejam progredindo muito na implementação nativa dos recursos do ES2015, há um pegadinha. Para usar o conjunto completo de recursos hoje, você precisará transcompilar seu código de volta para ES5 para que ele possa ser interpretado pelos navegadores atuais. Felizmente, existem ferramentas como o Babel que tornam esse processo muito simples.
Como usar o Babel no processo de compilação
O Babel permite que você pegue o JavaScript escrito usando recursos ES2015 e o transpile para ES5 para que ele funcione em navegadores que não são compatíveis com esses recursos. É possível adicionar o Babel ao seu processo de compilação dessa forma.
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'));
});
O único recurso que o Babel não consegue transcompilar são os Módulos. Os módulos no ES6 permitem criar classes e exportar / importar classes entre arquivos. Para transcompilar módulos, transmita o JavaScript pelo Browserify, que mesclará os arquivos e os transmitirá pelo Babelify, uma versão do Babel que pode processar a saída do 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/'));
});
Vários arquivos JavaScript
O exemplo acima exige que você defina um arquivo específico, o que pode ser um pouco complicado. Matt faz o seguinte no Gulp para pesquisar e transcompilar arquivos que terminam com .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 verificações de estilo
Há poucas opções ao inspecionar o código em busca de possíveis problemas e conformidade de estilo.
JSHint e JSCS
JSHint e JSCS são as ferramentas mais comuns usadas para a verificação de estilo JavaScript de hoje.
A JSHint destacará todos os possíveis problemas no seu código e destacará todos os padrões geralmente considerados como práticas não recomendadas.
O JSCS verifica o estilo do código, incluindo itens como garantir que apenas tabulações ou espaços sejam usados e que os espaços sejam colocados em locais consistentes.
Para usar JSHint e JSCS no código ES2015, você precisa adicionar "esnext": true
aos seus arquivos .jshintrc
e .jscsrc
ESLint
O ESLint (link em inglês) é uma ferramenta alternativa de linter e verificador de estilo. Essa ferramenta está ganhando mais vapor e tem alguns recursos interessantes em relação ao JSHint, por exemplo, a capacidade de indicar ambientes para os quais o JavaScript foi escrito e de definir o nível de erro / aviso para problemas específicos.
O ESLint é totalmente personalizável e oferece regras de inspeção personalizadas para você controlar se as opções podem ser desativadas ou reduzidas usando os arquivos de configuração. Além disso, se você estiver usando o React, o ESLint também funcionará com o JSX.
Configurar o ESLint no seu processo de compilação também não é muito difícil.
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...
});
A equipe do Babel mantém babel-estlint,
uma ferramenta que permite inspecionar qualquer código válido do Babel usando ESLint. Embora o ESLint
oferece suporte a analisadores personalizados, algumas das sintaxes com suporte do Babel não são diretamente
compatíveis com ESLint. Portanto, essa é outra opção, se você precisa de ainda mais
flexibilidade. Isso pode ser configurado personalizando a seção parser
do
arquivo .eslintrc
:
{
"parser": "babel-eslint",
"rules": {
"strict": 0
}
}
Dan Abramov tem um ótimo artigo sobre a configuração do ESLint e do babel-eslint em Lint Like It's 2015. Também aborda como integrar o SublimeLinter-eslint ao fluxo de trabalho para suporte a inspeção ES2015 no Sublime Text.
Qual plataforma deve usar? Experimente e use o que funciona melhor para você.
Destaque de sintaxe ES2015
É claro que a sintaxe do seu código ES2015 deve ser destacada corretamente. Gostamos de usar o babel-sublime, que pode ser instalado pelo Controle de pacotes. Ao configurar, recomendamos que você o defina como padrão para todos os arquivos que precisam ser destacados para trabalhar. Isso inclui o JS, mas também poderá abranger o JSX se você estiver usando o React.
Como documentar o ES2015
Historicamente, usamos o JSDoc para documentar o código JavaScript. Ele tem problemas em aberto (link em inglês) para oferecer suporte ao ES2015 (devido a já ter sido abordado no JSDoc 3). No entanto, há um número crescente de alternativas disponíveis enquanto aguardamos a solução. O ESDoc é uma dessas opções, e Jonathan Creamer fez uma composição recente sobre o assunto que vale a pena ler.
Como criar arquivos Gulp.js com o Babel
Se você estiver usando Gulp no processo de compilação, agora será possível criar Gulpfiles com qualquer sintaxe compatível com o Babel. Fazemos isso no Web Starter
Kit (link em inglês),
e a configuração é relativamente simples. Usando uma versão recente do Gulp e da
CLI do Gulp, basta renomear gulpfile.js
como gulpfile.babel.js
, e o Gulp vai
interpretar e transcompilar seu gulpfile ES2015 usando o Babel automaticamente.
Recursos favoritos do ES2015
Módulos
Os módulos são uma maneira de exportar valores, funções e classes de um arquivo, de modo que você possa importá-los para outro.
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?');
}
}
Neste site, você encontra ótimos exemplos e explicações sobre os módulos.
Strings de modelo
As strings de modelo permitem substituir uma porta de uma string por uma variável.
// Simple string substitution
var name = "Brendan";
console.log('Yo, ${name}!');
// => "Yo, Brendan!"
O bom com as strings de modelo é que a substituição é uma execução de JavaScript, o que significa que é possível usar funções ou expressões inline.
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.
Saiba mais nesta postagem do blog útil de Addy (em inglês).
Literais de objetos abreviados
Com os literais de objeto, você não precisa definir a chave e o valor durante a criação de um objeto, caso a variável tenha o mesmo nome que a chave que você quer que o objeto tenha.
Ou seja:
function createObject(name, data) {
return { name: name, data: data };
}
Fica assim:
function createObject(name, data) {
return { name, data };
}
Nomes de propriedades computados
Esse recurso no ES2015 permite criar nomes de propriedades dinamicamente em um objeto. Os documentos do Mozilla são uma ótima fonte de informações e têm esse ótimo exemplo (em inglês).
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
Funções da seta gorjeta
As funções de seta de gordura permitem que você escreva funções de forma abreviada em que:
button.addEventListener('click', function(event) {
console.log('The button has received a click', event);
});
Fica assim:
button.addEventListener('click', (event) => {
console.log('The button has received a click', event);
});
Além de ter uma sintaxe mais curta, um ótimo recurso do uso de funções de seta multifacetadas é que o escopo do objeto é o mesmo da instrução de inclusão. Isso significa que você não precisa chamar .bind(this) na sua função nem criar uma var que seja igual a isto.
Há muitos outros exemplos no MDN.
Links para mais informações
Repositório de ferramentas ES6 do Addy
O Addy está ocupado mantendo uma lista de ferramentas ES2015. Se as ferramentas acima não são adequadas para você, talvez você esteja usando o Grunt em vez do Gulp, isso pode ter uma resposta para você.
https://github.com/addyosmani/es6-tools
O conteúdo acima também inclui links para outras ferramentas do Babel que podem ajudar durante o teste de unidade e além.
Livros para ler
Há dois livros que você pode conferir sem custo financeiro on-line para saber mais sobre a ES2015. Noções básicas sobre ECMAScript 6, escrito por Nicholas C. Zakas e Exploring ES6 escrito pelo Dr. Axel Rauschmayer.
Torre de Babel
Se você quiser aprender sobre os recursos do ES2015 na sua linha de comando, a tower-of-babel oferece uma série de exercícios que podem ser do seu interesse. Todos eles usam o Babel.
Outros recursos em caso de interesse: