Yeoman - Guia para criar e publicar um gerador
Tags: programming, productivity, webdev
Published: 2021-12-16 04:15:21

Neste artigo vou ensinar como criar seu gerador padrão no Yeoman onde irá facilitar sua vida ao iniciar um projeto poupando o trabalho de criar aquelas pastas como o mesmo nome e suas libs favoritas e claro otimizando seu tempo, lembrando que pode criar os geradores padrões para cada tipo de projeto seu (desde uma API até uma base landing page).

Yeoman é uma ferramenta de estrutura para aplicativos da web. Isso nos ajuda a permanecer produtivos, simplificando algumas das tarefas repetitivas que fazemos como desenvolvedores.

![Procurando Gerador](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oyeenvqkmaqmo4faxmo8.png)

### Requisitos

Nesse exemplo irei criar um gerador padrão para um CRUD utilizando Node.js com Typscript, Clean Architecture e conexão com banco de dados MySQL utilizando o Knex.

Para isso precisamos instalar o Node.js com NPM e Yeoman. Para baixar e instalar o Node.js / NPM, visite o site [clicando aqui](https://nodejs.org/) e siga as instruções. Já para instalar o Yeoman, visite o site do mesmo [clicando aqui](http://yeoman.io/). Precisaremos também de um repositório no GitHub, e uma conta no [NPM](https://www.npmjs.com/signup), certifique-se de ter os dois. 

![NPM sign in](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2nyizd60qqheg9kgm6gz.png)
 
### Iniciando os trabalhos

Agora que temos tudo que precisamos vamos criar nosso repositório no GitHub para nosso gerador

![Criando um repositório](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w817zfjo7jk1atxrg5cf.png)

Observe que o nome do repositório deve começar com `generator` e posteriormente o nome exclusivo para npm que você definiu, no nosso caso vai ser `crud-type-db`. Isso é necessário para publicar nosso gerador. Insira um nome exclusivo e uma descrição (⚠ O nome deve ser único)

Clique em `Create repository` quando terminar. Você pode inicializar o repositório com um arquivo `README` se desejar mas neste guia, adicionaremos todos os arquivos manualmente utilizando o GIT. Você pode verificar se o nome existe ou não digitando no search do site do NPM, digite `generator` + o nome que você definiu se aparecer um pacote com mesmo nome significa que você deve mudar o nome do seu pacote e se não já sabe.... só manter que vai ser sucesso.

Para a próxima etapa copie a URL do repositório fazendo dá seguinte forma: 

![Copiando link](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vsg6o04kxskucde7jpac.png)
 
### Inicializando o nosso repositório

Vamos clonar nosso repositório para funcionar localmente e para isso abra um terminal e clone o repositório que você criou. Exemplo:

```
$ git clone https://github.com/jhonywalkeer/generator-crud-type-db.git
Cloning into 'generator-crud-type-db.git'...
warning: You appear to have cloned an empty repository.
```

Use o URL copiado da etapa anterior, podemos ignorar o aviso sobre a clonagem de um repositório vazio uma vez que iremos criar arquivos em breve e confirmar as alterações quando terminarmos de testar o gerador localmente. Mude o diretório de trabalho para a pasta recém-clonada:

```
$ cd generator-crud-type-db
```

Vamos inicializar o npm (lembrando que clonamos um repositório vazio e vamos criar a estrutura localmente e posteriormente atualizaremos as alterações para o repositório):

```
$ npm init
```

Vamos passo a passo em cada opção. Primeiro, insira um nome, pressione Enter para o nome padrão:

```
name: (generator-crud-type-db) <press enter>
```

Agora insira um número de versão:


```
version: (1.0.0) 0.0.1
```

A seguir, uma descrição para o gerador:

```
description: <Descrição de sua escolha> 
```
Para as próximas opções, deixe o ponto de entrada como o valor padrão (index.js), o comando test (vazio) e o repositório git.


```
entry point: (index.js) <press enter>
test command: <press enter>
git repository: (https://github.com/jhonywalkeer/generator-crud-type-db.git) <press enter>
```

A próxima etapa é importante, na seção de palavras-chave, precisamos adicionar algumas palavras-chave para tornar nosso gerador pesquisável e uma delas que deve ser adicionada é `yeoman-generator`. Yeoman usa esta palavra-chave para encontrar geradores também podemos adicionar outras palavras-chave relacionadas:

```
keywords: yeoman-generator, nodejs, typescript, crud, database, generator
```
Finalmente, adicione informações sobre o autor e uma licença.

```
author: SEU NOME <seu e-mail(se quiser colocar)>
license: (ISC) MIT
```
Ao pressionar <enter>, as informações inseridas serão exibidas para confirmação.

Agora que nosso arquivo `package.json` foi gerado, agora podemos instalar quaisquer dependências e a primeira obrigatória é  `yeoman-generator`.

```
$ npm install yeoman-generator
```

Para nosso exemplo, também precisamos instalar as seguintes dependências:

```
$ npm install decamelize uppercamelcase
```

### Adicionando arquivos

Um gerador é basicamente um módulo Node.js e ele está profundamente vinculado ao sistema de arquivos, à árvore de diretórios. Quando você chama seu gerador, um gerador padrão chamado `app` é executado. Cada `sub-gerador` está contido em uma pasta com seu próprio nome. Por exemplo, quando você executa o `app` sub-gerador, o Yeoman procura os arquivos dentro de uma app/pasta. Em nosso exemplo, não vamos usar nenhum sub-gerador, então vamos criar uma app/pasta e colocar os arquivos necessários dentro dela.

Vamos criar a pasta e um primeiro arquivo necessário:

```
$ mkdir app
$ touch app/index.js
```

No `index.js` arquivo, vamos inicializar nosso módulo Node.js e este módulo será executado por padrão quando chamarmos nosso gerador. Ainda precisamos fazer algo importante... Precisamos dizer ao Node.js onde encontrar nossos arquivos geradores e para isso abra seu arquivo `package.json` e adicione as seguintes linhas:

```
"files": [
  "app"
]
```

Não vou entrar em muitos detalhes sobre a funcionalidade específica de nosso gerador de exemplo. Vamos começar a adicionar um construtor básico agora. Abra seu `app/index.js` arquivo e copie / cole o seguinte código:

```
'use strict';
const Generator = require('yeoman-generator');
module.exports = class extends Generator {
  constructor(args, opts) {
    super(args, opts);
    this.log('Initializing...');
  }
  start() {
    this.log('Do something...');
  }
};
```

Salve o arquivo e vou te explicar.. Este é o construtor mais básico, ele apenas exibirá uma mensagem de log para o terminal (veremos isso na próxima etapa) observe que, além do construtor, também adicionei um `start()` método. Se você não adicionar pelo menos um método, receberá um erro quando quiser testá-lo. Isso é bastante simples, o módulo é inicializado pelo construtor e, em seguida, o `start()` método é executado. Se adicionarmos mais métodos, eles serão executados um após o outro.

Consulte o site do (Yeoman)[http://yeoman.io/authoring/index.html] para obter mais informações sobre sub-geradores, construtores e muito mais.

### Teste
Podemos testar o gerador em nosso ambiente local antes de publicá-lo e disponibilizá-lo ao público.

```
$ npm link
 > spawn-sync@1.0.15 postinstall / Users / jhonywalkeer / dev / generator-crud-type-db / node_modules / spawn-sync 
> node postinstall
generator-crud-type-db@0.0.1 / Users / jhonywalkeer / dev / generator-crud-type-db 
```

Parabéns! Seu primeiro gerador está pronto para funcionar! Vamos ver como isso funciona.

```
$ yo generator-crud-type-db
Initializing...
Do something...
```

Bom trabalho! Se você vir essas duas mensagens simples, significa que seu gerador está funcionando perfeitamente e pronto para ser publicado. Se você vir algum erro, verifique novamente se adicionou pelo menos um método ao módulo.

###Interação do usuário e modelos

Claro, antes de publicar nosso gerador, queremos fazer algo extra. Vamos fazer duas coisas básicas agora:

1. Faça alguma interação com o usuário
2. Copiar um arquivo

Vamos começar pedindo ao usuário para inserir um nome para o nosso módulo. Abra o `app/index.js` arquivo e substitua o conteúdo do `start()` método adicionando o seguinte:

```
this.prompt([
    {
      type    : 'input',
      name    : 'name',
      message : 'Enter a name for the new component (i.e.: myNewComponent): '
    }
  ]).then( (answers) => {
    // create destination folder
    this.destinationRoot(answers.name);
  });
```

Aqui fazemos duas coisas: primeiro, pedimos ao usuário para inserir um nome e, em seguida, criamos uma pasta com esse nome. Salve o arquivo e execute-o:

```
$ yo generator-crud-type-db
Initializing...
? Enter a name for the new component (i.e.: myNewComponent):  testDevto

```

Agora, faça um `ls` (ou verifique o diretório onde executou o comando) e veja se uma pasta chamada `testDevto` foi criada.

Vamos copiar um arquivo, um template html por exemplo. Precisamos criar uma pasta na `app/` para salvar nossos arquivos de origem que serão copiados para a pasta de destino.

```
$ mkdir app/templates
$ touch app/templates/index.html
```
Precisamos copiar esses arquivos. Adicione o seguinte no `index.js` arquivo, após a `this.destinationRoot(answers.name);` linha:

```
this.fs.copyTpl(
  this.templatePath('index.html'),
  this.destinationPath(answers.name + '.html')
);
```
O anterior irá procurar um arquivo nomeado `index.html` dentro da pasta de modelos padrão e copiá-lo para a pasta de destino. Ao mesmo tempo, estamos alterando o nome do arquivo para ser igual ao nome do componente. Se executarmos novamente, veremos algo como:

```
$ yo generator-crud-type-db
Initializing...
? Enter a name for the new component (i.e.: myNewComponent):  testM
   create testDevto.html
```

Se listarmos o conteúdo da `testMe` pasta, veremos nosso novo arquivo lá. Podemos fazer muito mais, vamos fazer algo extra agora. Já que estamos copiando um modelo, seria bom se pudéssemos inserir / alterar o conteúdo do arquivo, certo? Podemos fazer isso usando EJS (JavaScript eficaz. Veja [sobre aqui](http://ejs.co/) ).

Abra o `app/templates/index.html` arquivo e adicione o seguinte:

```
<div> 
  <p> <% = mensagem%> </p> 
</div>
```

Usando EJS, vamos substituir a `message` tag por outra. Pode ser qualquer coisa, mas vamos ao clássico hello world :). No `app/index.js` arquivo, passe um parâmetro extra para o `copyTpl` método:

```
{ message: 'Hello world!' }
```

Deve ser assim:

```
this.fs.copyTpl(
  this.templatePath('index.html'),
  this.destinationPath(answers.name + '.html'),
  { message: 'Hello world!' }
);
```
Vamos rodar nosso gerador novamente:

```
$ yo generator-crud-type-db
Initializing...
? Enter a name for the new component (i.e.: myNewComponent):  testMe
   conflict testDevto.html
? Overwrite testDevto.html? overwrite
   force testDevto.html
```

Observe que, como estamos usando a mesma `testDevto` pasta, há um conflito porque o `testDevto.html` arquivo do nosso teste anterior já existe. Vamos apenas sobrescrever. Quando solicitado, responda `y` e pressione Enter para substituir o arquivo html.

Agora, se olharmos para o conteúdo do arquivo html, vemos que a `message` tag foi substituída por nossa mensagem hello world.

```
$ cat testDevto/testDevto.html
<div>
  <p>Hello world!</p>
</div>
```
Nosso gerador está pronto para ser publicado.

### Publicar

Vamos primeiro enviar as alterações para o GitHub. Adicione os arquivos, envie-os por `push` para o repositório (não se esqueça de excluir a pasta `testDevto` antes de fazer isso, ou apenas adicione um `.gitignore` arquivo para ignorá-lo).

```
$ rm -rf testDevto
$ git add .
$ git commit -S -a -m "chore: remove folder testDevto"
$ git push -u origin master
```

No exemplo que estou usando, também adicionei os arquivos `README.md`, `LICENSE.md`, `.gitignore`, bem como outros modelos que uso para o `generator-crud-type-db`.

Agora é hora de publicar o gerador:

```
$ npm publish
+ generator-crud-type-db@0.0.2
```

###Usando seu gerador

Depois de criar seu gerador, é fácil usá-lo. Basta instalá-lo como faria com qualquer outro gerador Yeoman. Você pode compartilhar seu gerador com sua equipe ou apenas usá-lo para acelerar alguns desses processos mecânicos diários.

Instale-o primeiramente:

```
$ npm install -g generator-crud-type-db
```
e para usá-lo:

```
$ yo crud-type-db
```

Yeoman nos permite fazer muito mais coisas, este é apenas um começo básico para entender o básico. Esse pacote que foi criado em conjunto foi excluído (depois de ter detonado a estrutura hahah) então você pode se frustar ao tentar procurá-lo porém estarei publicando em meu GitHub para que possa ver o código.

Fontes onde pesquisei esse conteúdo:

- https://yeoman.io/
- https://yeoman.io/authoring/
- https://yeoman.io/learning/index.html
- https://yeoman.io/codelab/index.html
- https://github.com/yeoman/generator-webapp