Slush, o novo Yeoman

Ultimamente tem se falado muito em melhoras no workflow. Cada desenvolvedor tem o seu método de trabalhar. Mas todos possuem algo em comum: acham um saco ter que copiar os arquivos de um lado para o outro para ter que criar um novo projeto. É neste momento que entram os generators.

Yeoman e Boilerplates

Foi pensando nisso que nos últimos anos (2~3) passaram a surgir vários boilerplates e generators, esse ultimo mais especificamente utilizando o Yeoman. Sim, nossa vida melhorou muito. Cada projeto que iniciamos sempre possui uma estrutura inicial padrão, e agora você não precisa mais copiar e colar arquivos de um lado para o outro.

Se você ainda não conhece o Yeoman, ele é uma stack client-side feito em NodeJS que permite que você crie generators de várias aplicações web, utilizando as mais diversas tecnologias. Atualmente a comunidade já criou quase 700 generators, além dos official generators e também dos que não aparecem em nenhumas dessas listas.

O Yeoman utiliza do Grunt para fazer o scaffolding e do Bower para baixar as dependências dos projetos.

Apesar dos muitos generators, criar um generator exige muito cuidado, além de ler um pouco a documentação do Yeoman.

Com o surgimento do GulpJS, um task runner, assim como o Grunt, foi criado o Slush, um generator que utiliza o Gulp, ao invés do Grunt, além de ter um proposta mais simples.

Começando com o Slush

O Slush depende apenas do GulpJS e de seus plugins. Para quem já mexeu com o Gulp, não terá muita dificuldade. Se você ainda não mexeu com o Gulp, aconselho o artigo do Leonardo Souza, Bye bye Grunt.js, hello Gulp.js!.

Instalando o Slush

Para instalar o Slush, basta ter o NodeJS instalado na sua máquina. Se você já tem, basta instalar o Slush de modo global:

$ [sudo] npm install -g slush

Criando seu primeiro generator

Como exemplo, nosso projeto irá gerar um scaffolding para trabalhar com a stack MEAN. Todo generator para Slush deve ter o prefixo slush-. Então vamos criar uma pasta chamada slush-mean e entrar nela:

$ mkdir slush-mean && cd slush-mean

Criação do arquivo package.json

Então primeiro vamos criar um arquivo chamado package.json, parecido com esse:

{
  "name": "slush-mean",
  "version": "0.1.0",
  "description": "Generate a simple web project using M.E.A.N. stack",
  "main": "slushfile.js",
  "keywords": [
    "slushgenerator",
    "mean",
    "express",
    "mongo",
    "node",
    "angular"
  ],
  "dependencies": {
    "gulp": "~3.5.6",
    "gulp-template": "~0.1.1",
    "gulp-install": "~0.1.1",
    "gulp-conflict": "~0.1.1",
    "gulp-rename": "~1.2.0",
    "underscore.string": "~2.3.3",
    "inquirer": "~0.4.1"
  },
  "author": "Seu Nome",
  "license": "MIT"
}

Vale ressaltar dois pontos/linhas importantes nesse arquivo:

  • No main devemos colocar o slushfile.js, pois assim como o Grunt e o Gulp, o Slush utiliza um arquivo de configuração próprio. Além do mais, o main é utilizado pelo npm para executar esse arquivo quando o módulo for instalado (veremos isso a seguir).
  • Nas keywords é importante o uso da palavra-chave slushgenerator para que seu gerador apareça na lista “oficial”, lá no site do Slush.

Instalar as dependências

Depois que o arquivo package.json foi criado, vamos instalar as dependências:

$ [sudo] npm install

Criar arquivo slushfile.js

Vamos agora criar um arquivo chamado slushfile.js na raiz, junto com seu package.json. O arquivo explica-se por si só, mas depois dele vou colocar algumas observações:

/*
 * slush-mean
 * https://github.com/seu-nome/slush-mean
 *
 * Copyright (c) 2014, Seu Nome
 * Licensed under the MIT license.
 */

'use strict';

var gulp     = require('gulp');
var install  = require('gulp-install');
var conflict = require('gulp-conflict');
var template = require('gulp-template');
var rename   = require('gulp-rename');
var _        = require('underscore.string');
var inquirer = require('inquirer');

gulp.task('default', function(done) {

  var prompts = [{
    name: 'appName',
    message: 'What the name of project?'
  }, {
    name: 'appDescription',
    message: 'What the description?'
  }, {
    name: 'appVersion',
    message: 'What the version?',
    default: '0.1.0'
  }, {
    name: 'appAuthor',
    message: 'Name of author?'
  }, {
    name: 'appEmail',
    message: 'Author e-mail?'
  }];

  inquirer.prompt(prompts,
    function(answers) {
      if (!answers.appName) {
        return done();
      }
      answers.appNameSlug = _.slugify(answers.appName)
      answers.appAuthorSlug = _.slugify(answers.appAuthor)
      gulp.src(__dirname + '/templates/**')
        .pipe(template(answers))
        .pipe(rename(function(file) {
          if (file.basename[0] === '_') {
            file.basename = '.' + file.basename.slice(1);
          }
        }))
        .pipe(conflict('./'))
        .pipe(gulp.dest('./'))
        .pipe(install())
        .on('end', function() {
          done();
        });
    });
});

Alguns pontos a serem observados:

  • Na linha onde tem /templates/ **, é nessa pasta que irá ficar os arquivos a serem “extraidos”
  • Note que nas perguntas, existe a opção de colocar uma resposta “default” quando o cara só der ENTER

Criando os arquivos a serem gerados

Essa parte é simples. Coloque dentro da pasta templates tudo que irá ser extraído. E agora vem a parte boa. Quando você quiser “printar” o valor de uma resposta, simplesmente coloque <%= nomeDaVariavelResposta %> nos arquivos.

Por exemplo, crie eum arquivo chamado package.json dentro da pasta templates:

{
  "name": "<%= appnameslug="" %="">",
  "description": "<%= appdescription="" %="">",
  "version": "<%= appversion="" %="">",
  "author": {
    "name": "<%= appauthor="" %="">",
    "url": "<%= appemail="" %="">"
  }
}

Um ponto importante, é que os arquivos lá da pasta templates que começam com ., como por exemplo o .gitignore você deverá substituir por _, ficando assim _gitignore. Mas não se preocupe, na hora que ele é gerado/compilado, ele se é renomeado para .gitignore. Isso é feito pelo gulp-rename para que os arquivos de configuração que começam com o ., não tenham seu comportamento padrão.

Quando o generator for utilizado, o Slush/Gulp nada mais irá fazer que extrair tudo que está na pasta templates para a raiz e deletar os arquivos que ali estavam (slushfile.js, package.json, …).

Estrutura de arquivos

slush-mean/
├── templates/
│   ├── gulpfile.js
│   ├── package.json
│   └── ...
├── slushfile.js
└── package.json

Testando e Publicando no NPM

Para você testar seu gerador, utilize o comando npm link ., isso irá criar um alias no seu npm/node. Agora você já pode testar seu generator. Crie outra pasta fora dessa estrutura e rode o comando slush mean. Para publicar nos registros oficias do NPM, utilize o comando npm publish. Se tiver dúvidas de como publicar um módulo, consulte o próprio site do NPM.

Conclusão

Vimos que com apenas dois arquivos conseguimos construir um generator like a Yeoman, só que bem mais simples. Eu mesmo criei um generator que irei explicar em outro post como foi feito, bem como o modo de usar.

Esse artigo parte do princípio de que você já tenha alguma familiariada com Node, NPM, Task Runner, Terminal entre outras coisas.

Qualquer dúvida, fique a vontade para publicar seu comentário!