nuxt × atomic design でのコンポーネントを量産していく過程で、
.vue
ファイルと storybookのjsファイルを hygen で生成していくフローが楽だったので、やり方をメモ。
storybookのドキュメント通りに始めると、
出力サンプルが /stories/
dirができ、そこに書いてくような形で始まる。
前提として、 .stories.js
と .vue
ファイルは同じdirに収納していく形にする方が、管理しやすいように思います。(違う?)
手動でやると大変、ミスもあるので、hygenを使い、この部分を自動化します。
hygenとは
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
にコマンドを追加。今回はこんな感じで追加してみる。
{
"scripts": {
"storybook": "start-storybook -s ./static -p 3001 --ci",
"build-storybook": "build-storybook -c .storybook"
}
}
configをつくる
/.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.vue
と MyButton.stories.js
<template>
<button class="my-button"><slot></slot></button>
</template>
<script>
export default {
name: 'MyButton'
}
</script>
<style scoped>
.my-button{}
</style>
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
へアクセスすると無事見れました。
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
// 対話式の設問で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" ...等(パスカルケース)'
},
// ・・・ プロジェクト毎、必要に応じて 設問を追加 ・・・
]
---
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 %>/>'
}))
---
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 等のテストファイルも、テンプレも作っておくと捗ります。
もっと良いアイデアや使い方をご存知の方、コメントを頂ければ幸いです。