🏭
PLOPでComponentファイルを雛形から生成しよう
こんにちはmofmofでエンジニアをしているshwldです。
Componentを作るときに、storybook, jest, graphqlなどのファイルをひとまとめにして作ることが増えてきました。
└ components
└ todo
└ TodoCreateForm
├ index.tsx
├ TodoCreateForm.graphql
├ TodoCreateForm.stories.tsx
├ TodoCreateForm.test.tsx
├ TodoCreateForm.tsx
これを解消するためにHygenを使っていたのですが、PLOPのほうが好きだなと感じたので共有します。
PLOPでコンポーネントを作る体験
⋊> yarn plop component
...
? src/components/{path please}
? component name please
?
の質問に回答していくとコンポーネントが作成されます。
todo
TodoDeleteButton
と回答すると、
✔ ++ /src/components/todo/TodoDeleteButton/index.tsx
✔ ++ /src/components/todo/TodoDeleteButton/TodoDeleteButton.tsx
✔ ++ /src/components/todo/TodoDeleteButton/TodoDeleteButton.stories.tsx
✔ ++ /src/components/todo/TodoDeleteButton/TodoDeleteButton.test.tsx
✔ ++ /src/components/todo/TodoDeleteButton/TodoDeleteButton.graphql
このように生成されます。
この雛形を作るための設定
propfile.jsでpromptとテンプレートの定義を行います。
/plopfile.js
module.exports = function (
/** @type {import('plop').NodePlopAPI} */
plop
) {
plop.setGenerator('component', {
description: 'react component',
prompts: [
// 入力させたい値につけたnameをactionsやtemplate内で参照できます
{
type: 'input',
name: 'parentPath',
message: 'src/components/{path please}',
},
{
type: 'input',
name: 'name',
message: 'component name please',
},
],
actions: [
{
type: 'add',
path: 'src/components/{{parentPath}}/{{name}}/index.tsx',
templateFile: 'plop-templates/component/index.tsx.hbs',
},
{
type: 'add',
path: 'src/components/{{parentPath}}/{{name}}/{{name}}.tsx',
templateFile: 'plop-templates/component/Component.tsx.hbs',
},
{
type: 'add',
path: 'src/components/{{parentPath}}/{{name}}/{{name}}.stories.tsx',
templateFile: 'plop-templates/component/Component.stories.tsx.hbs',
},
{
type: 'add',
path: 'src/components/{{parentPath}}/{{name}}/{{name}}.test.tsx',
templateFile: 'plop-templates/component/Component.test.tsx.hbs',
},
{
type: 'add',
path: 'src/components/{{parentPath}}/{{name}}/{{name}}.graphql',
templateFile: 'plop-templates/component/Component.graphql.hbs',
},
],
});
};
生成したいファイルの分だけテンプレートファイル(.hbs)を作成します。
テンプレート内で{{pascalCase name}}
, {{name}}
のようにして参照できます。またpascalCaseなどがデフォルトで利用できるようになっているのでよく使います。
/plop-templates/component/index.tsx.hbs
export * from './{{name}}';
/plop-templates/component/Component.tsx.hbs
import { ReactNode, VFC } from 'react';
export const {{pascalCase name}}: VFC<{ children?: ReactNode }> = () => {
return (
<div></div>
);
};
/plop-templates/component/Component.stories.tsx.hbs
// 略
/plop-templates/component/Component.test.tsx.hbs
// 略
/plop-templates/component/Component.graphql.hbs
// 略
好きなところ
- テンプレートと生成の設定が完全に分かれている
- promptで定義したnameをテンプレートと合わせるだけなので直感的に使える。生成のために書くコードが最小
TIPS
フォルダを選択させる
/propfile.js
const fs = require('fs');
const features = fs
.readdirSync('src/features')
.map((it) => ({ name: it, value: it }));
module.exports = function (
/** @type {import('plop').NodePlopAPI} */
plop
) {
plop.setGenerator('query', {
description: 'graphql query',
prompts: [
{
type: 'list',
name: 'name',
message: 'feature name please',
choices: features,
},
],
...略
このようにpromptで選択できる
? feature name please (Use arrow keys)
❯ todo
account
index.ts等のファイルにexportだけ追記したい
└ components
└ Hoge
├ index.tsx
├ Button.tsx
├ Card.tsx
├ ListItem.tsx
上記のようなフォルダで
/components/Hoge/index.tsx
export * from 'Button.tsx'
export * from 'Card.tsx'
export * from 'ListItem.tsx'
のようなindex.tsxが存在しているとき。
Buttonを生成したら、index.tsxに1行書き加えてもらいたいときありますよね。
そのようなときは、actionsにappend
を書きます
propfile.js
...
actions: [
{
type: 'add',
path: 'src/components/{{module}}/{{name}}.tsx',
templateFile: 'plop-templates/component.tsx.hbs',
},
{
type: 'append',
path: 'src/components/{{module}}/index.tsx',
template: "export * from './{{name}}';",
},
]
...
まとめ
使いやすい!おすすめです
Discussion
この記事はテンプレートファイルを5つ用意する必要があるが、初めて自動生成ツールを使う自分にとってはもう少しわかりやすく書いてほしかった、わかってしまえば簡単なツールだと思う。
コメントありがとうございます。
templateFileがファイル数分必要な点や全体的に説明が足りてなかったです。
取り急ぎ、必要なファイルが5つあることを追記しました。