logo

scaffdogでサクッとファイルテンプレートを生成する

2023-11-22
a year ago

開発環境

  • next 13.4.10
  • scaffdog 3.0.0

前提

scaffdogを利用したことのない方向けの記事です。

本題

NextやReactのプロジェクトではとても浸透しているStorybookですが、たいてい新しいコンポーネントを追加するとき、お決まりのテンプレートを作成することになります。

そんなときに、コマンドと簡単な対話をするだけでサクッとファイルができるscaffdogが便利です。

簡単なセットアップを紹介します。

今回は、src/components配下に新しいファイル、ディレクトリを配置する想定にしています。

例えば、buttonコンポーネントを作成するときは、以下の配置でファイルが生成されます。

src
 └── components
       |
       └── button                   *new
             ├── button.tsx         *new
             ├── button.stories.tsx *new
             └── index.ts           *new



手順① ライブラリインストール

$ yarn add -D scaffdog

手順② 初期設定

$ npx scaffdog init
? Please enter a document name. component

Setup of scaffdog 🐶 is complete!

  ✔ .scaffdog/config.js
  ✔ .scaffdog/component.md

Now you can do scaffold by running `$ scaffdog generate`.

Please refer to the following documents and customize it.
https://scaff.dog/docs/templates

ドキュメント名を聞かれるので、今回は/componentsディレクトリのファイルを想定して、componentとしておきます。

ファイルは自動で生成されます。

手順③ テンプレートの設定ファイル編集

---
name: 'component'
root: 'src/components'
output: '.'
questions:
  dir: 'Please enter a directory name.'
  exist:
    confirm: 'Directory already existed?'
    initial: false
  name: 'Please enter a component name.'
  story:
    confirm: 'Do you need a story?'
    initial: true
---

# `{{ inputs.dir }}/index.ts`

```typescript
export * from './{{ inputs.name }}';
{{ if inputs.exist }}{{ read output.abs }}{{ end }}
```

# `{{ inputs.dir }}/{{ inputs.name }}.tsx`

```typescript
import type { ReactNode } from 'react';

export type {{ inputs.name | pascal }}Props = {
  children: ReactNode;
};

export const {{ inputs.name | pascal }} = ({ children }: {{ inputs.name | pascal }}Props) => {
  return <>{children}</>;
};
```

# `{{ !inputs.story && '!' }}{{ inputs.dir }}/{{ inputs.name }}.stories.tsx`

```typescript
import { {{ inputs.name | pascal }}, type {{ inputs.name | pascal }}Props } from './{{ inputs.name }}';

import type { Meta, StoryFn } from '@storybook/react';

const meta: Meta = {
  title: 'Components/{{ inputs.name | pascal }}',
  component: {{ inputs.name | pascal }},
};

export default meta;

const Template: StoryFn<{{ inputs.name | pascal }}Props> = (props) => <{{ inputs.name | pascal }} {...props} />;

export const Default = Template.bind({});

Default.args = {};
```

ポイント

questionsで入力値(y/n)によって、後の処理を分けています。

existでは、指定したディレクトリがすでに存在するかを確認し、存在する場合は既存のファイルの先頭行に追記するようにしています。

storyでは、Storybookファイルを任意で生成するようにしています。

手順④ コマンドを追加

{
	...省略,
  "scripts": {
    "scaffdog": "npx scaffdog generate --force"
  },
  ...省略,
}

yarn scaffdogで実行できるようにします。

--forceに関しては、確認のプロンプトを表示せずにファイルの書き込みをさせるようにしています。既存ファイルへの追記を行う場合、常に聞かれてしまうので、省略する意図があります。

さいごに

existでディレクトリ確認をして処理を分けていますが、ここは改善の余地があります。

できれば自動的に処理を分けたいです(が、ライブラリで提供されているヘルパーなどではできなさそう?)

今回の実装例であげたような、シンプルなものであれば十分scaffdogで事足りそうです。

参照