古い環境にStorybookを入れる

かなり昔に作っていたWebサイトを更新することがあり、勉強がてらStorybookを入れてみるかと思ったら、諸々のバージョンを更新する必要があったので実行した内容を残しておきます。

環境をまるっと作り変えるにはあまりにもコストがかかりすぎるので、既存環境のバージョンを更新してやっていきます。

ちなみに、
・Webpackがv4なので更新が必要
↓
・Storybookのインストール時にNode.js 18以上が必要と言われるので更新が必要
↓
・Node.jsのバージョンを上げる＋Apple Siliconなのでnode-sassからdart-sassに移行が必要
という流れで更新する必要がある箇所が増えていきました。

環境自体の更新を放置し続けていたので仕方がないですね。

## 開発環境

- gulp
    - pug
    - sass
- webpack

## Storybookの必須環境

- Webpack ≥ 5.0
- Storybook ≥ 8.0
- Node.js ≥ 18

## 主なバージョンアップデートのまとめ
    
|  | 現在のバージョン | 更新後のバージョン |
| --- | --- | --- |
| Node.js | 12.22.12 | 20.9.0 |
| webpack | 4.42.0 | 5.96.1 |
| webpack-cli | 3.3.11 | 5.1.0 |
| webpack-stream | 5.2.1 | 7.0.0 |
| gulp-sass | 4.0.2 | 5.1.0 |
| node-sass | 4.13.1 | 削除 |
| sass | - | 1.80.6 |
| storybook | - | 8.4.1 |

## 注意事項

バージョンを更新するそれぞれの工程時に、ビルドされたファイルの差分を確認してください。

 minifyされているファイルだと差分が分からないこともあると思いますが、その場合はブラウザ上での動作確認をしっかりと行なってください。

## webpackのv5導入

※色んなプラグイン入れたりしている方は公式の移行ページをご確認ください。

https://webpack.js.org/migrate/5/

1.以下コマンドで最新バージョンをインストール

```bash
$ npm install webpack@latest webpack-cli@latest webpack-stream@latest
```

※gulpでwebpack-streamを使用している場合、必ず更新をしてください。古いとうまくビルドされません。

2.`webpack.config.js`のdevtoolの指定で以下が使われていたら変更

```diff
-devtool: "cheap-module-eval-source-map",
+devtool: "eval-cheap-module-source-map",
```

3.jsファイルを更新してうまくビルドがされたら完了

## Node.jsの更新

Node.jsのバージョン管理をしていることを前提としています。

1.もし上げたいバージョンが入っていなければインストールする

2.`.node-version`ファイルのバージョンを更新する

```diff
-12.22.12
+20.9.0
```

3.Nodeのバージョンを確認し、変わっていれば完了

```diff
$ node -v
20.9.0
```

## node-sassからdart-sassへの移行

1.node-sassとgulp-sassのアンインストール

```diff
$ npm uninstall node-sass gulp-sass
```

2.sassとgulp-sassの最新をインストール

```diff
$ npm install -D sass gulp-sass@latest
```

3.`gulpfile.js`を以下のように更新する

```diff
-const sass = require("gulp-sass");
-sass.compiler = require('node-sass');

+const sass = require("gulp-sass")(require("sass"));
```

4.各scssファイルの記述をdart-sassの記法に合わせて修正をする
以下のコマンドを使用すると自動で変更してくれます。私の場合、useで一部おかしな記述が入ってしまっていたので、そこだけ手動で直しました。

```bash
$ npm install -g sass-migrator
$ sass-migrator module --migrate-deps src/scss/main.scss
```

主に修正されたのは以下です。

- `@import`を`@use`に変更
- sassの変数、mixinの読み込み方を変更
- `map-get`関数をモジュールインポートして使用するように変更

5.scssファイルを更新してうまくビルドがされたら完了

## Storybookの導入

ようやく本題に入ります。ここからも少し続きます。

1.storybookのインストール

```bash
$ npx storybook@latest init
```

2.typeを選ぶかと聞かれるので`y`を入力する

```bash
$ Do you want to manually choose a Storybook project type to install? … y
```

3.typeの選択肢が出てくるので、`html`を選択する

```bash
$ Please choose a project type from the following list: html
```

4.インストールが終わるとローカルホストが立ち上がり、ページが自動で開く

![スクリーンショット 2024-11-05 0.18.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47351/c958b679-cdd5-57d1-660e-15e6e4562deb.png)


### 定義ファイルをpugに変更する

上記でインストールは完了ですが、開発環境でpugを利用しているので設定を追加します。
最初に生成されるButtonコンポーネントのコードをpugに変換してみたので、参考にどうぞ。

1.pugを使うためのpackageをインストール
```bash
$ npm i -D pug pug-runtime storypug
```

2.`.storybook/main.js`にstorypugを追加

```diff
/** @type { import('@storybook/html-webpack5').StorybookConfig } */
const config = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [
    "@storybook/addon-webpack5-compiler-swc",
    "@storybook/addon-essentials",
    "@chromatic-com/storybook",
    "@storybook/addon-interactions",
+    "storypug",
  ],
```

3.`src/stories/Button.pug`を作成

```html
mixin Button (props = {})
  - const mode = props.primary ? 'storybook-button--primary' : 'storybook-button--secondary';
  - const size = props.size !== '' && props.size !== undefined  ? props.size : 'medium'
  - const className = ['storybook-button', `storybook-button--${size}`, mode].join(' ');
  - const backgroundColor = props.backgroundColor !== '' ? props.backgroundColor : ''
  button(class=className style=props.backgroundColor ? `background-color: ${props.backgroundColor}` : "")= props.label
```

4.`src/stories/Button.stories.js`を更新

```jsx
import { fn } from "@storybook/test";

import startCase from "lodash/startCase";
import { renderer } from "storypug";
import Button from "./Button.pug";
import "./button.css";

const { html } = renderer({ startCase });

export default {
  title: "Button",
  tags: ["autodocs"],
  argTypes: {
    backgroundColor: { control: "color" },
    label: { control: "text" },
    onClick: { action: "onClick" },
    primary: { control: "boolean" },
    size: {
      control: { type: "select" },
      options: ["small", "medium", "large"],
    },
  },
  // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
  args: { onClick: fn() },
};

const Template = (args) => {
  return html(Button, args);
};

export const Primary = Template.bind({});
export const Secondary = Template.bind({});
export const Large = Template.bind({});
export const Small = Template.bind({});

Primary.args = {
  label: "Primary Button",
  primary: true,
};
Secondary.args = {
  label: "Secondary Button",
};
Large.args = {
  label: "Secondary Button",
  size: "large",
};
Small.args = {
  label: "Secondary Button",
  size: "small",
};
```

### 自前のcssをstorybookで読み込む

すでに1つのmain.scssがあるのでこちらを読み込んでスタイルが当たるようにします。

1.sass-loader等をインストール

```bash
$ npm install -D sass-loader css-loader style-loader
```

2.`.storybook/main.js`に設定を追加

```diff
const config = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [
    "@storybook/addon-webpack5-compiler-swc",
    "@storybook/addon-essentials",
    "@chromatic-com/storybook",
    "@storybook/addon-interactions",
    "storypug",
  ],
  framework: {
    name: "@storybook/html-webpack5",
    options: {},
  },
+  webpackFinal: async (config) => {
+    config.module.rules.push({
+      test: /\.scss$/,
+      use: [
+        "style-loader",
+        "css-loader",
+        {
+          loader: "sass-loader",
+          options: {
+            implementation: require("sass"),
+          },
+        },
+      ],
+    });
+    return config;
+  },
};
```

3.記述しているclassを使って、スタイルが当たるかどうかを確認し、問題なければ完了

cssで参照している画像のパスで怒られたりしましたが、相対パスに変えて解決させました。


### その他

ドキュメントからコードをコピーする際、ビルドされたHTMLしか取れないので、こちらの記事を参考にをやってみようと思います。

[https://zenn.dev/periorin/articles/c307cd5142bc96#コピーするコードをpug変換する](https://zenn.dev/periorin/articles/c307cd5142bc96#%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B%E3%82%B3%E3%83%BC%E3%83%89%E3%82%92pug%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B)

![スクリーンショット 2024-11-05 0.19.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/47351/d37ede7d-5395-7478-0984-d3b076316b83.png)


## 最後に

storybookを始められるところまでやってきました。あとはコンポーネントのファイルを作っていくだけです。

今回の作業でエラーが出た際、生成AIをフルに活用しました。久しぶりに触る開発環境でしたが色々と忘れていたので助かりました。
ただ、提案されるconfigファイルの書き方が古い情報だったりすることもあるので、公式ドキュメントも参考にしてください。


## 参考資料

https://sass-lang.com/documentation/breaking-changes/import/

https://storybook.js.org/docs/get-started/frameworks/web-components-webpack5?renderer=web-components#getting-started

https://storybook.js.org/addons/storypug