Garbanzo Note

コードジェネレーター「hygen」入門 ~ブログのテンプレート生成を作る~

December 18, 2020

目次


hygenとは?

Hygen

hygenをテンプレートを元にコード(ファイル)を生成することが出来るジェネレーターである

あらかじめ用意・設定したテンプレートをベースにファイルを自動生成することができる スケーラブルなコードジェネレーター


hygenセットアップ

インストール

yarn add -D hygen

初期化

% hygen init self
Loaded templates: node_modules/hygen/src/templates
       added: _templates/generator/help/index.ejs.t
       added: _templates/generator/with-prompt/hello.ejs.t
       added: _templates/generator/with-prompt/prompt.ejs.t
       added: _templates/generator/new/hello.ejs.t

実行すると_templatesディレクトと配下にディレクトリとファイルが生成される

├── _templates
│   └── generator
│       ├── help
│       │   └── index.ejs.t
│       ├── new
│       │   └── hello.ejs.t
│       └── with-prompt
│           ├── hello.ejs.t
│           └── prompt.ejs.t
├── package.json
└── yarn.lock
  • _templates/generatorがジェネレター名
  • _templates/generator/help or /new or /with-promptがジェネレターのアクション名 アクションディレクトリの配下に生成するコードのテンプレート等は配置する
  • .ejs.tとなっているファイルがコードテンプレート
  • prompt.ejs.tがプロンプト設定ファイル
generator //ジェネレータ名
├── help //アクション名
├── new 
└── with-prompt

このhygen generatorジェネレーターを使い、新しくジェネレーターを生成する


ジェネレーターを作る

generatorジェネレーターには、newwith-promptが用意してある

% hygen generator help

Loaded templates: hygen
help:
hygen generator new --name [NAME] --action [ACTION]
hygen generator with-prompt --name [NAME] --action [ACTION]
  • newは、実行時に引数を渡しでコード生成するジェネレーター
  • with-promptは、対話式でコード生成するジェネレーターを生成する

今回は、対話式のwith-promptで作る

% hygen generator with-prompt --name sample --action new 

nameにジェネレータ名を指定し、actionにそのコマンドのアクション名を指定する 今回、sampleジェネレーターのnewアクションを作成する

% hygen generator with-prompt --name sample --action new

Loaded templates: _templates
       added: _templates/sample/new/hello.ejs.t
       added: _templates/sample/new/prompt.js

これによりhygen sample new実行可能な対話式コードジェネレターが作成される 生成されたファイル一覧

% tree _templates 
_templates
├── generator
└── sample
    └── new
        ├── hello.ejs.t
        └── prompt.js

各ファイルについて

hello.ejs.t

生成するファイルのテンプレートになるファイル

拡張子にあるとおりejs記法で記述する

hello.ejs.t

---
to: app/hello.js //①
---
//②
const hello = \```
Hello!
This is your first prompt based hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
\```

console.log(hello)

① 生成するファイルを指定する

---以下に生成するコードを記載する

prompt.js

prmpt.jsは、プロンプトファイルで対話(コマンド実行)する内容を記述する

enquirerがプロンプトランナーとして内部で使用されている

page/new/prompt.js

// see types of prompts:
// https://github.com/enquirer/enquirer/tree/master/examples
//
module.exports = [
  {
    type: 'input', //①
    name: 'message', //②
    message: "What's your message?" //③
  }
]

① 入力方式を指定可能。他に、selecttogglelistなど

ejs.t内で使用する変数名

③ 質問内容を記載する

必要な質問分配列で{type, name, message}を追加していく 他にvalidationなど追加する事も可能

実行してみる

% hygen sample new
✔ What's your message? · Hello!

Loaded templates: _templates
       added: app/hello.js

app/hello.jsが生成される ※message聞かれるがテンプレートファイルに使用の定義がないので生成ファイルには何も反映されない

% tree app 
app
└── hello.js

% cat app/hello.js 
const hello = \```
Hello!
This is your first prompt based hygen template.

Learn what it can do here:

https://github.com/jondot/hygen
\```

console.log(hello)

GatsbyのBlogジェネレーターを作る

ここから本題

やりたいことは、

  • blog newコマンドでcontent/blog配下にblogファイル(.md)を作成する
  • 記事名など対話式で指定できるようにする(以下に記載)

プロンプトの内容

メッセージ Type 備考
記事名を入力 input 必須
記事の日付 input デフォルトは今日
ドラフトで生成するか? toggle デフォルトはtrue。ドラフトとは記事を公開するかのフラグ
記事の説明 input
タブ名を入力 list 必須

1.ジェネレーターの作成

hygen blog newでBlog生成できるようにするので

% hygen generator with-prompt --name blog --action new

でジェネレーターを作成する

% hygen generator with-prompt --name blog --action new

Loaded templates: _templates
       added: _templates/blog/new/hello.ejs.t
       added: _templates/blog/new/prompt.js
% tree _templates 

_templates
├── blog
│   └── new
│       ├── hello.ejs.t
│       └── prompt.js

2.プロンプトを作成する

つづいて、プロンプトの作成

_templates/blog/new/prompt.jsをプロンプトの定義を追加する

// see types of prompts:
// https://github.com/enquirer/enquirer/tree/master/examples
//
module.exports = [
  {
    type: 'input',
    name: 'blogName',
    message: "記事名を入力",
    validate: (answer) => { //①
      if(!answer){
        return "必須です。入力してください";
      }
      return true
    }
  },
  {
    type: 'input',
    name: 'date',
    message: "記事の日付を入力",
    hint:'yyyy-MM-dd',
    validate: (answer) => { //②
      if(answer && !RegExp('^([0-9]{4})-([0-9]{2})-([0-9]{2})$').test(answer)){
        return "yyyy-MM-dd形式で入力して下さい。"  
      }
      return true
    }
  },
  {
    type: 'toggle',
    name: 'draft',
    message: "ドラフトで生成する?",
    enabled: 'Yes',
    disabled: 'No'
  },
  {
    type: 'input',
    name: 'description',
    message: "記事の説明を入力",
  },
  {
    type: 'list',
    name: 'tags',
    message: "タブ名を入力",
    hint:'カンマ(,)区切りで入力',
    validate: (answer) => { //③
      if(!answer.length){
        return "必須です。入力してください";
      }
      return true
    }
  }
]

パラメータtypenamemessageを追加する

  • type: 入力方式を設定
  • name: テンプレートファイルで使用する変数名
  • message: 対話式プロントの質問内容

① Blog名がないと生成に困るので、validateパラメータに必須チェックを追加

② 日付はyyyy-MM-dd形式で入力してほしいのでフォーマットバリデーションを追加

③ タブ名も①同様、必須にしたいのでvalidate追加

3.テンプレートファイルを作成する

まずはファイル名が、_templates/blog/new/hello.ejs.t なので_templates/blog/new/blog.ejs.t に変更

---
to: content/blog/<%= blogName.replace(/\//g, '_') %>/index.md //①
---
---
title: <%= blogName ? blogName : '' %>
date:  "<%= date ? date : h.moment().format('YYYY-MM-DD') %>" //②
description: <%= description ? description : '' %>
tags: <% for (const tag of tags) { %> //③
    - <%- tag %><% } %>
drafts: <%= drafts %>
---
--------------------------------------------------
## <%= blogName %>

テンプレートファイルないでは、ejs記法を使用することが出来る。 <%= 変数名 %>でpromept.jsで定義したnameパラメータが変数名となり入力値として使用できる

/がディレクトリ名にあると階層がズレてしまうので_に変更している

② デフォルトをmomentを使用して設定する

dataの入力がない場合、デフォルトとして今日を設定する為、momentを利用している。 利用する為には、.hygen.jsを用意して以下の定義を行う。

const moment = require('moment');

module.exports = {
    helpers: {
        moment
    }
};

とすることで、テンプレートファイルでh.moment()で使用することが出来る

③ for分を使用してtags:を表示

フォーマットが変な感じになっているが理由があり例えば以下のようにした場合

tags: 
  <% for (const tag of tags) { %>
    - <%- tag %>
  <% } %>
↓  
tags: 

    - hello

    - hygen

と余計な空白が入ってしまう為、詰めて定義している

4.実行してみる

コマンドは、hygen blog new

% hygen blog new                                                                                               
✔ 記事名を入力 · コードジェネレーター「hygen」入門
✔ 記事の日付を入力 · 2020-12-16
✔ ドラフトで生成する? · No / Yes
✔ 記事の説明を入力 · コードジェネレーターhygenの導入・使用について
✔ タブ名を入力 · hygen, 入門

Loaded templates: _templates
       added: content/blog/コードジェネレーター「hygen」入門/index.md

生成を確認

% cat content/blog/コードジェネレーター「hygen」入門/index.md 
---
title: コードジェネレーター「hygen」入門
date:  2020-12-16
description: コードジェネレーターhygenの導入・使用について
tags: 
    - hygen
    - 入門
drafts: true
---
----------------------------------------

ディレクトリの変更

デフォルトは、_templates導入する場合わかりにくいことがあるので ディレクトリを変更することが可能

.hygen.jsを追加し、下記コードを定義する

module.exports = {
  templates: `${__dirname}/hygen`
};

_templatesディレクトリ名をhygenに変更する

これでhygenディレクトリに変更される


Garbanzo

Webエンジニアの備忘録です。 学んだことをアウトプットしています。

合計記事数
25