4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

nuxt.js × Atomic Design での component 作成にhygenを使ってみる

Last updated at Posted at 2019-07-14

nuxt × atomic design でのコンポーネントを量産していく過程で、
.vueファイルと storybookのjsファイルを hygen で生成していくフローが楽だったので、やり方をメモ。

storybookのドキュメント通りに始めると、
出力サンプルが /stories/ dirができ、そこに書いてくような形で始まる。

前提として、 .stories.js.vue ファイルは同じdirに収納していく形にする方が、管理しやすいように思います。(違う?)
手動でやると大変、ミスもあるので、hygenを使い、この部分を自動化します。

hygenとは

hygen.png

Hygenとはコマンドラインからファイルを生成する対話式のコードジェネレーターのパッケージです。

参考 : https://qiita.com/usagi-f/items/ea4ecf7ec6a6b52567e3

nuxtとstorybookをセットアップ

まずはnuxtをセットアップ

サクッといれます。

$ npx create-nuxt-app <project-name>
$ cd <project-name>
$ npm run dev

動いた。

storybookのインストールとコンポーネントの作成

公式のドキュメント を参考に、今回は Manual setup(手動方式)でいれてみる。

スクリプトを入れる

$ npm install @storybook/vue --save-dev

$ npm install vue --save
$ npm install vue-loader vue-template-compiler @babel/core babel-loader babel-preset-vue --save-dev

package.jsonにコマンドを追加。今回はこんな感じで追加してみる。

package.json
{
  "scripts": {
    "storybook": "start-storybook -s ./static -p 3001 --ci",
    "build-storybook": "build-storybook -c .storybook"
  }
}

configをつくる

/.storybook/config.js を作成。

/.storybook/config.js
import { configure } from '@storybook/vue';

function loadStories() {
  // こちらを消し
  // require('../stories/index.js');

  // /components/ 配下の .stories.js を対象
  const req = require.context('../components', true, /\.stories\.js$/);
  req.keys().forEach(filename => req(filename));

}

configure(loadStories, module);

実際にはここでaddons.jsに、storybookのaddonを入れていくと思いますが、割愛。

vue開発で約に立ちそうなaddonの参考 :
https://qiita.com/asdfghjkl1234/items/3c7580718715c275a729

Atomic Design のルールに沿って、コンポーネントを作ってみる。

プロジェクト毎に微妙にルールが異なると思いますが、今回は/components/配下を以下のような、atom等の各粒度の配下に、「サブカテゴリ」を設けたルールにしてみます。
.stories.js も各コンポーネントとセットで定義していく。

components
├── atoms
│   ├── buttons
│   │   └── MyButton
│   │       ├── MyButton.stories.js  // ← ここ
│   │       └── MyButton.vue
│   ├── texts
│   │   └── MyText
│   │       ├── MyText.stories.js  // ← ここ
│   │       └── MyText.vue
│   ├── forms
│   ├── ... その他プロジェクトで必要なサブカテゴリ
│   └── others
├── molecules
├── organisms
├── pages
└── templates

最小限のコンポーネントを作成。
例として MyButton.vueMyButton.stories.js

MyButton.vue
<template>
  <button class="my-button"><slot></slot></button>
</template>

<script>
export default {
  name: 'MyButton'
}
</script>

<style scoped>
.my-button{}
</style>
MyButton.stories.js

import { storiesOf } from '@storybook/vue'
import MyButton from './MyButton'

storiesOf('atoms/buttons/MyButton', module)
  .add('default', () => ({
    components: { MyButton },
    template: '<MyButton>私はボタンです</MyButton/>'
  }))

必要ファイルができたら以下で実行。

$ npm run storybook

package.jsonで指定した http://localhost:3001 へアクセスすると無事見れました。

スクリーンショット 2019-07-14 18.53.36.png

hygenをセットアップ

こちらも 公式ドキュメント通りに

$ cd <project-name>
$ npm i -g hygen
$ hygen init self

すると以下のような dir が作られる。

_templates
└── generator
    ├── help
    │   └── index.ejs.t
    ├── new
    │   └── hello.ejs.t
    └── with-prompt
        ├── hello.ejs.t
        └── prompt.ejs.t

/_templates/generator/ 以下はサンプルファイルの様子。
hygenのジェネレーターは以下のようなルールになってるらしい。

hygen <generator> <action> [NAME]

サンプルは無視して、 Atomic Designのコンポーネントを作るので、以下のような3ファイルでテンプレートファイルを準備する。

_templates
└── component
    └── new
        ├── prompt.js
        ├── story.ejs.t
        └── vue.ejs.t
prompt.js
// 対話式の設問でAtomic Designのコンポーネントを定義します

module.exports = [
  {
    type: 'select',
    name: 'category',
    message: '作成する Atomic Design のカテゴリを選択',
    choices: ['atoms', 'molecules', 'organisms', 'templates', 'pages']
  },
  {
    type: 'select',
    name: 'subcategory',
    message: 'サブカテゴリを選択',
    choices: [
      'no-subcategory', //サブカテゴリに属さない
      'buttons',
      'texts',
      'forms',

      // ... プロジェクトに必要なパーツのサブカテゴリをすべて定義する

      'others'
    ]
  },
  {
    type: 'input',
    name: 'componentname',
    message: 'component名を入力',
    hint: '"FormInputText" ...等(パスカルケース)'
  },

  // ・・・ プロジェクト毎、必要に応じて 設問を追加 ・・・

]
story.ejs.t
---
to: components/<%= category %><% if(subcategory && subcategory!=='no-subcategory'){ %>/<%= subcategory %><% } %>/<%= componentname || 'unnamed'%>/<%= componentname || 'unnamed'%>.stories.js
---
import { storiesOf } from '@storybook/vue'
import <%= componentname %> from './<%= componentname %>'
storiesOf('<%= category %><% if(subcategory && subcategory!=='no-subcategory'){ %>/<%= subcategory %><% } %>/<%= componentname %>', module)
  .add('default', () => ({
    components: { <%= componentname %> },
    template: '<<%= componentname %>/>'
  }))

vue.ejs.t
---
to: components/<%= category %><% if(subcategory && subcategory!=='no-subcategory'){ %>/<%= subcategory %><% } %>/<%= componentname || 'unnamed'%>/<%= componentname || 'unnamed'%>.vue
---
<template>
</template>

<script>
export default {
  name: '<%= componentname %>'
}
</script>

<style scoped>
</style>

hygenを使ってみる

ここまでできたら、hygenコマンドをつかってコンポーネントを作ってみる。

$ hygen component new

上記を実行すると対話式でコンポーネント作成が始まるので、質問に順に答えると、
nuxtの/components/内に新しいファイルが、Atomic Designとして設定したルール通りで新規作成されます。

アイデア次第ではもっと便利に

実際の開発では、templateにもっと大量に設定が追加されるので、新規作成はより便利に感じます。
storybookだけでなく、 jest 等のテストファイルも、テンプレも作っておくと捗ります。

もっと良いアイデアや使い方をご存知の方、コメントを頂ければ幸いです。

4
4
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
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?