ちびのはてな

「ちび(猫)」と「キノコ」から生まれた「ちびキノコ」。ドラゴンボール最強!純粋なサイヤ人のように生きたいと思っているモノ作りを楽しむ人です。IT技術で少しでも多くの人が笑顔になってくれたらいいなと。

Nuxt.js x Class API x Storybook (x SCSS)

前提・環境

$ node -v
v14.17.3

$ npm -v
7.19.1

$ yarn -v
1.22.10

$ nuxt -v
@nuxt/cli v2.15.8
  • Nuxt.js x TypeScript x Class API のプロジェクトが用意されていること

Class API の Nuxt.js で Storybook を使ってみる

まずはデフォルトで動作確認

1. まずは https://storybook.js.org/docs/react/get-started/install に従って Storybook をインストール

$ npx sb init

2. デフォルト状態で動作確認

$ yarn storybook

3. 問題ないことを確認

f:id:chibi929:20211001055526p:plain
Storybook (Default)

まぁ。。。Options API の例だし、できるよね。

続いて、↑ で生成された Vue ファイルを Class API 向けに編集する

1. 編集作業

// ./stories/Button.vue

  <template>
    <button type="button" :class="classes" @click="onClick" :style="style">{{ label }}</button>
  </template>

- <script>
- import './button.css';
+ <script lang="ts">
+ import { Vue, Component, Prop } from 'vue-property-decorator'

- export default {
-   name: 'my-button',
+ @Component
+ export default class Input extends Vue {

-   props: {
-     label: {
-       type: String,
-       required: true,
-     },
-     primary: {
-       type: Boolean,
-       default: false,
-     },
-     size: {
-       type: String,
-       default: 'medium',
-       validator: function (value) {
-         return ['small', 'medium', 'large'].indexOf(value) !== -1;
-       },
-     },
-     backgroundColor: {
-       type: String,
-     },
-   },
+   @Prop({ type: String, required: true })
+   private readonly label!: string
+   @Prop({ type: Boolean, default: false })
+   private readonly primary!: boolean
+   @Prop({
+     type: String,
+     default: 'medium',
+     validator: (value) => {
+       return ['small', 'medium', 'large'].indexOf(value) !== -1
+     },
+   })
+   private readonly size!: string
+   @Prop({ type: String })
+   private readonly backgroundColor!: string

-   computed: {
-     classes() {
-       return {
-         'storybook-button': true,
-         'storybook-button--primary': this.primary,
-         'storybook-button--secondary': !this.primary,
-         [`storybook-button--${this.size}`]: true,
-       };
-     },
-     style() {
-       return {
-         backgroundColor: this.backgroundColor,
-       };
-     },
-   },
+   private get classes() {
+     return {
+       'storybook-button': true,
+       'storybook-button--primary': this.primary,
+       'storybook-button--secondary': !this.primary,
+       [`storybook-button--${this.size}`]: true,
+     }
+   }
+   private get style() {
+     return {
+       backgroundColor: this.backgroundColor,
+     }
+   }

-   methods: {
-     onClick() {
-       this.$emit('onClick');
-     },
-   },
+   private onClick() {
+     this.$emit('onClick')
+   }
- };
+ }
    </script>

+ <style scoped>
+ .storybook-button {
+   font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+   font-weight: 700;
+   border: 0;
+   border-radius: 3em;
+   cursor: pointer;
+   display: inline-block;
+   line-height: 1;
+ }
+ .storybook-button--primary {
+   color: white;
+   background-color: #1ea7fd;
+ }
+ .storybook-button--secondary {
+   color: #333;
+   background-color: transparent;
+   box-shadow: rgba(0, 0, 0, 0.15) 0px 0px 0px 1px inset;
+ }
+ .storybook-button--small {
+   font-size: 12px;
+   padding: 10px 16px;
+ }
+ .storybook-button--medium {
+   font-size: 14px;
+   padding: 11px 20px;
+ }
+ .storybook-button--large {
+   font-size: 16px;
+   padding: 12px 24px;
+ }
+ </style>

2. そして動作確認!

$ yarn storybook

問題なく行ける!!

この調子で SCSS もやってしまえ!

Style を SCSS にする

1. 編集作業

// ./stories/Button.vue

- <style scoped>
+ <style lang="scss" scoped>

2. 動作確認

$ yarn storybook
ERROR in ./stories/Button.vue?vue&type=style&index=0&id=43fc969c&lang=scss&scoped=true& (./node_modules/vue-docgen-loader/lib??ref--12!./node_modules/vue-loader/lib??vue-loader-options!./stories/Button.vue?vue&type=style&index=0&id=43fc969c&lang=scss&scoped=true&) 49:0
Module parse failed: Unexpected token (49:0)
File was processed with these loaders:
* ./node_modules/vue-docgen-loader/lib/index.js
* ./node_modules/vue-docgen-loader/lib/index.js
* ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
  • ここに来て、エラー!

3. ということでググる

ということでいじる

// ./.storybook/main.jsmain.js

+ const path = require('path');

module.exports = {
    "stories": [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)"
    ],
    "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials"
-   ]
+   ],
+   webpackFinal: async (config, { configType }) => {
+     // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
+     // You can change the configuration based on that.
+     // 'PRODUCTION' is used when building the static version of storybook.
+ 
+     // Make whatever fine-grained changes you need
+     config.module.rules.push({
+       test: /\.scss$/,
+       use: ['style-loader', 'css-loader', 'sass-loader'],
+       include: path.resolve(__dirname, '../'),
+     });
+ 
+     // Return the altered config
+     return config;
+   },
}

4. 動作確認

$ yarn storybook

いけた!

assets/scss/styles.scss に定義してある変数を使ってみる

1. Vue ファイルの編集作業

// ./stories/Button.vue

  .storybook-button--primary {
-   color: white;
-   background-color: #1ea7fd;
+   color: $color_light;
+   background-color: $color_primary;
  }

2. 動作確認

$ yarn storybook
ERROR in ./stories/Button.vue?vue&type=style&index=0&id=43fc969c&lang=scss&scoped=true& (./node_modules/css-loader/dist/cjs.js!./node_modules/vue-loader/lib/loaders/stylePostLoader.js!./node_modules/sass-loader/dist/cjs.js!./node_modules/vue-loader/lib??vue-loader-options!./stories/Button.vue?vue&type=style&index=0&id=43fc969c&lang=scss&scoped=true&)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable.
╷
59 │   color: $color_light;
│          ^^^^^^^^^^^^

3. Storybook の設定周り編集作業

// ./.storybook/main.js

    config.module.rules.push({
    test: /\.scss$/,
-   use: ['style-loader', 'css-loader', 'sass-loader'],
+   use: [
+     'style-loader',
+     'css-loader',
+     'sass-loader',
+     {
+       loader: 'sass-resources-loader',
+       options: {
+         resources: ['assets/scss/styles.scss'],
+       },
+     },
+   ],
    include: path.resolve(__dirname, '../'),
    })

4. 動作確認

$ yarn storybook

f:id:chibi929:20211001064622p:plain
Storybook (頑張ったやつ)

最後に

  • Storybook をインストールしたことで、 yarn dev 実行時に CSS-Loader 周りにエラーが出る
  • yarn add -D css-loader@4.2.0 とバージョン指定することで解決できる

yarn devyarn storybook 別々のビルドになるので、両方確認しなきゃいけないことがわかった。