⚒️

google/zxでテンプレートからReactコンポーネントをつくる

2022/10/30に公開

ReactやVueなどを利用した、コンポーネント指向でのfrontend開発を行なっていると、コンポーネントが増えるたびに毎回複数のファイルを作成するのが面倒です。

なのであらかじめ用意したテンプレートのファイル群から、コンポーネントを生成するスクリプトを作成し、自動化を行いましょう。

とはいえ、「シェルスクリプト?俺はjsしか書けん!!」という方もいるかもしれないので、jsでシェルスクリプトがかけるgoogle/zxを利用してお手軽にコンポーネントのジェネレータを作成します。

https://github.com/google/zx

導入

yarn add zx -d

zxっていうパッケージ名、カッコよすぎる。

テンプレートファイルの作成

今回は、/components配下に、フォルダを作成し、その中に以下のファイルを作成する簡単な例にします。

 L components/
   L Example/
     L Example.module.scss
     L Example.test.tsx
     L Example.tsx
     L index.tsx

また、各ファイルの中身を適当に記述しておきます。

Example.tsx
import { VFC } from 'react'
import styles from './Example.module.scss'

const Example: VFC<Props> = () => {
  return (
    <>
      Example
    </>
  )
})

export default Example
index.tsx
export { default } from './Example'
Example.test.tsx
import { render } from '@testing-library/react'
import Example from './Example'

describe('Example', () => {
  it('test', async () => {
    // test case
  })
})

ここで、コンポーネント固有の部分は生成時にsedで置換することになるので、Exampleなどで統一するようにしておきます。

実行の準備

適当なところに実行するためのスクリプトファイルをつくります。
拡張子はmjsを利用すると、await が top-level で利用できるのでそうします。

touch bin/create-component.mjs

実行はzx {ファイル名}でできるのでscriptを追加しておきます。

package.json
"scripts" {
  ...
  "create": "zx ./bin/create-component.mjs"
},

これでyarn run createで実行できる状態になりました。

生成ファイルの記述

あとはスクリプトの中身を書いていくだけです。

完成の例はこちら

create-component.mjs
import 'zx/globals'

// パスカルケースかチェック
const validatePascal = (str) => {
  const regex = new RegExp('^[A-Z].*[a-zA-Z]+$')
  if (!regex.test(str)) {
    throw new Error('Component must be pascal case. (ex: ComponentName)')
  }
}

// componentの入力を受け付ける
const component= await question("Type component name: ")
validatePascal(component)

// components/{component}のフォルダ作成
await $`mkdir ./components/${component}`

// components/Example配下のファイルを文字列置き換えと同時にrenameして使う
await $`sed 's/Example/${component}/g' ./components/Example/Example.tsx > ./components/${component}/${component}.tsx`
await $`sed 's/Example/${component}/g' ./components/Example/index.tsx > ./components/${component}/index.tsx`
await $`sed 's/Example/${component}/g' ./components/Example/Example.module.scss > ./components/${component}/${component}.module.scss`

// 終了

これで、テンプレートのExampleが入力したコンポーネントの文字列に置き換えられたファイルが生成されます。

await questionで簡単に対話形式のコマンドが書けるのでコンポーネントの名前入力を受け付けられたり、jsの記法でエラーを投げられます。

await $で囲むことでシェルスクリプトをそのまま書くこともできます。

結局、シェルスクリプト書かないといけないじゃんと思うかもしれませんが、jsで条件分岐やバリデーションやができるのは書きやすかったです。

まとめ

今回はシンプルな例でしたが、atomic designっぽいコンポーネント設計や、厳密なルールが設定されている場合にはより自動化の恩恵を受けられると思うので試してみてください。

Discussion