LoginSignup
27
23

More than 3 years have passed since last update.

[React]コンポーネントを作るときに他からコピーしてくる作業を自動化するCLIツールを作る

Last updated at Posted at 2020-11-12

TL;DR

Reactでコンポーネントを新しく作るとき、Storybookやテストも作成するのであれば、ディレクトリを作成してから、
index.ts, Component.tsx Component.stories.tsx Component.spec.tsx
と4ファイルくらい作成することになると思いますが、
毎回これらを手動で作成して、他のコンポーネントからimport文とかをコピーしてくるのは面倒なので、CLIツールを作成して、コマンド一発で出来るようにします。

コードはこちら

作ったもの

ディレクトリ構成

AtomicDesign想定です。

.
├── package.json
├── src
│   └── components
│       └── atoms
│           └── Button
│               ├── Button.spec.tsx
│               ├── Button.stories.tsx
│               ├── Button.tsx
│               └── index.ts
└── tools
    ├── componentTemplates
    │   ├── Component.tsx
    │   ├── Spec.tsx
    │   ├── Story.tsx
    │   └── index.ts
    └── createComponent.js

コード

テンプレート作成

まず、環境に合わせて ./tools/componentTemplates/ 以下に、作成したいファイルのテンプレートを配置します。
このテンプレートをリネームして、必要な場所にコピーする感じです。

テンプレートはこちらを参照してください。

script作成

コマンドライン引数 オプション -C で、コンポーネントの粒度とコンポーネント名を受け取ります。

以下はコマンドのhelpです。

Usage: create-component [options]

Options:
  -C, --component [dir/Component]  The name of the component to be created (ex) atoms/Button
  -h, --help                       display help for command
  • 引数が不正である場合はエラー(atoms, molecules, organismsしか許容しない)
  • すでにコンポーネントが存在しているときはエラー(上書きしない)
  • ディレクトリが存在しないとき(/molecules/ など未作成の場合)は新規作成

します。

コードは以下です。

const { program } = require("commander");
const fs = require("fs");

program.option(
  "-C, --component [component name]",
  "The name of the component to be created (ex) atoms/Button"
);

program.parse(process.argv);

if (!program.component) {
  program.help();
}

const argument = program.component.split("/");
const dir = argument[0];
const component = argument[1];

if (!["atoms", "molecules", "organisms"].includes(dir)) {
  console.error(
    "ERROR: Only 'atoms', 'molecules', and 'organisms' can be specified."
  );
  return;
}

// If the directory is not yet created, create it.
if (!fs.existsSync(`./src/components/${dir}`)) {
  fs.mkdirSync(`./src/components/${dir}`);
}

const templates = [
  "./tools/componentTemplates/index.ts",
  "./tools/componentTemplates/Component.tsx",
  "./tools/componentTemplates/Story.tsx",
  "./tools/componentTemplates/Spec.tsx",
];

const dests = [
  `./src/components/${dir}/${component}/index.ts`,
  `./src/components/${dir}/${component}/${component}.tsx`,
  `./src/components/${dir}/${component}/${component}.stories.tsx`,
  `./src/components/${dir}/${component}/${component}.spec.tsx`,
];

fs.mkdirSync(`./src/components/${dir}/${component}`);

// Error when a component already exists
templates.forEach((template, index) => {
  fs.copyFileSync(
    template,
    dests[index],
    fs.constants.COPYFILE_EXCL,
    (error) => {
      if (error) {
        throw error;
      }
    }
  );
  console.log(`✨ Create component template ${dests[index]}`);
});

package.jsonに追記

package.jsonのscriptsに、

    "create-component": "node ./tools/createComponent.js"

を追記して完了です。

使用例

$ yarn create-component -C atoms/Icon

✨ Create component ./src/components/atoms/Icon/index.ts
✨ Create component ./src/components/atoms/Icon/Icon.tsx
✨ Create component ./src/components/atoms/Icon/Icon.stories.tsx
✨ Create component ./src/components/atoms/Icon/Icon.spec.tsx

これでめんどくさい作業から開放されました!

27
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
23