Docker + Laravel + Vite + Vue3環境へStorybookを導入
既存のInertiaの開発環境でStorybookも使えるようにしたい
構成
バックエンド(LaravelやRails) + モダン JavaScriptライブラリの構築を一つのリポジトリでまかなえるInertiaというのを使っていて、開発環境全体がDockerコンテナにいる。
Viteがすでに動作しているので、ここへ@storybook/builder-vite
を追加したい。
- Laravel Sail
- Docker
- Larabel
- Inertia
- Vite
- Vue3
達成したいこと
- Storybookに、Vueコンポーネントをimportしてカタログにしたい。
- HerokuかNetlifyで
build-storybook
をデプロイしたい。
Viteは既にうごいているので、Storybookと@storybook/builder-viteの導入から。
Docker Desktopを起動し、Sailを立ち上げるコマンドを実行。
sail up -d
続いてDockerコンテナ内で bashを起動する
sail shell
準備ができたので、パッケージを導入する。
npx sb init --builder storybook-builder-vite
initまでは無事に実行でき、ルートへ.storybook
とstories
のディレクトリとファイルが生成された。
パッケージのバージョンが噛み合わないエラー
initは成功したが、storybookの起動はエラーで失敗。
※このエラーの解決は、もうすこし後ろの「パッケージのバージョンが噛み合わないエラー:解決」
npn run storybook
> storybook
> start-storybook -p 6006
info @storybook/vue3 v6.5.13
info
info => Loading presets
ERR! TypeError: vite.createFilter is not a function
ERR! at viteReact (/var/www/html/node_modules/@vitejs/plugin-react/dist/index.cjs:231:21)
ERR! at pluginConfig (/var/www/html/node_modules/@storybook/builder-vite/dist/vite-config.js:82:36)
ERR! at processTicksAndRejections (node:internal/process/task_queues:96:5)
ERR! at async commonConfig (/var/www/html/node_modules/@storybook/builder-vite/dist/vite-config.js:66:18)
ERR! at async createViteServer (/var/www/html/node_modules/@storybook/builder-vite/dist/vite-server.js:10:24)
ERR! at async Object.start (/var/www/html/node_modules/@storybook/builder-vite/dist/index.js:64:14)
ERR! at async Promise.all (index 0)
ERR! at async storybookDevServer (/var/www/html/node_modules/@storybook/core-server/dist/cjs/dev-server.js:203:28)
ERR! at async buildDevStandalone (/var/www/html/node_modules/@storybook/core-server/dist/cjs/build-dev.js:120:31)
ERR! at async buildDev (/var/www/html/node_modules/@storybook/core-server/dist/cjs/build-dev.js:174:5)
このIssueが、まさにそれっぽい。
パッケージどうしのバージョンが噛み合っていないことが原因らしい。
(まだ、どれとどれが対象なのかは、わかっていない)
DockerコンテナのNode.jsを18へアップデート
パッケージバージョンかみ合わせ問題、TypeError: vite.createFilter is not a function
の調査で行き詰まった。
何かあったときはNodeのバージョンが原因のことが多いので
ためしにv16.5
を LTEの 18.12
までアップデートしてみることにした。
NODEで16と記載されているデータを探すと、/docker/8.1/Dockerfile
に記述がみつかった。
これを変更して再構築してみる。[1]
sail build --no-cache
実行すると、しばらくいろんなコマンドが流れた後…失敗
(省略)
#7 1.031 Ign:1 http://security.ubuntu.com/ubuntu impish-security InRelease
#7 1.075 Ign:2 http://archive.ubuntu.com/ubuntu impish InRelease
#7 1.270 Err:3 http://security.ubuntu.com/ubuntu impish-security Release
#7 1.270 404 Not Found [IP: 91.189.91.39 80]
#7 1.315 Ign:4 http://archive.ubuntu.com/ubuntu impish-updates InRelease
#7 1.678 Ign:5 http://archive.ubuntu.com/ubuntu impish-backports InRelease
#7 1.910 Err:6 http://archive.ubuntu.com/ubuntu impish Release
#7 1.910 404 Not Found [IP: 185.125.190.39 80]
#7 2.166 Err:7 http://archive.ubuntu.com/ubuntu impish-updates Release
#7 2.166 404 Not Found [IP: 185.125.190.39 80]
#7 2.487 Err:8 http://archive.ubuntu.com/ubuntu impish-backports Release
#7 2.487 404 Not Found [IP: 185.125.190.39 80]
#7 2.495 Reading package lists...
#7 2.519 E: The repository 'http://security.ubuntu.com/ubuntu impish-security Release' does not have a Release file.
#7 2.520 E: The repository 'http://archive.ubuntu.com/ubuntu impish Release' does not have a Release file.
#7 2.520 E: The repository 'http://archive.ubuntu.com/ubuntu impish-updates Release' does not have a Release file.
#7 2.520 E: The repository 'http://archive.ubuntu.com/ubuntu impish-backports Release' does not have a Release file.
ubuntuのアップデートやdocker-compose.ymlの編集も必要だった
お手上げだったので、このプロジェクトのDockerコンテナを設定してくれたエンジニアさんに助けてもらった。
差分をみると、/docker/8.1/Dockerfile
だけでなく/docker-compose.yml
も編集が必要だったり、ubuntu
のバージョンも関係していたよう。
更新してもらったデータで改めてsail build --no-cache
すると、成功。
sail up -d
からのsail shell
でコンテナのbashを起動し確認。
node -v
v18.12.0
-
行き詰まって色々試したので、この時点で、Sailを立ち上げる
sail up
は終了しており、Dockerコンテナ内で bashを起動するsail shell
もexit
で終了している ↩︎
パッケージのバージョンが噛み合わないエラー:解決
パッケージバージョンかみ合わせ問題、TypeError: vite.createFilter is not a function
の原因が見つかった。
IanVSさんによると、@storybook/builder-viteとviteのバージョンが噛み合ってないからエラーになっているとのこと。
最新版の@storybook/builder-vite
をvite
ver.3未満で実行しようとしたら発生する。
解決策は、このいずれか。
-
@storybook/builder-vite
をダウングレードする -
vite
をver3以上にアップデートする
さっそくViteのバージョンを確認してみたら、2.8
だった!
Viteを3.2にアップデートして解決
viteとその依存関係にあるパッケージをuninstall
し、改めてinstall
。最新版にアップデートした。
その後、SailやDockerコンテナを起動する一連のコマンドを実行してからStorybookを起動すると…
npn run storybook
...別のエラーで失敗した。
ともかく、@storybook/builder-vite
とvite
の依存関係については解消できた。(つづく)
Node.js 17以上にした際のOpenSSL互換エラー対応
Storybookの起動コマンドを実行すると、エラー。
> storybook
> start-storybook -p 6006
info @storybook/vue3 v6.5.13
info
info => Loading presets
info => Ignoring cached manager due to change in manager config
(node:633) ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
i 「wdm」: wait until bundle finished:
node:internal/crypto/hash:71
this[kHandle] = new _Hash(algorithm, xofLen);
^
Error: error:0308010C:digital envelope routines::unsupported
at new Hash (node:internal/crypto/hash:71:19)
at Object.createHash (node:crypto:133:10)
at module.exports (/var/www/html/node_modules/webpack/lib/util/createHash.js:135:53)
at NormalModule._initBuildHash (/var/www/html/node_modules/webpack/lib/NormalModule.js:417:16)
at handleParseError (/var/www/html/node_modules/webpack/lib/NormalModule.js:471:10)
at /var/www/html/node_modules/webpack/lib/NormalModule.js:503:5
at /var/www/html/node_modules/webpack/lib/NormalModule.js:358:12
at /var/www/html/node_modules/loader-runner/lib/LoaderRunner.js:373:3
at iterateNormalLoaders (/var/www/html/node_modules/loader-runner/lib/LoaderRunner.js:214:10)
at Array.<anonymous> (/var/www/html/node_modules/loader-runner/lib/LoaderRunner.js:205:4) {
opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ],
library: 'digital envelope routines',
reason: 'unsupported',
code: 'ERR_OSSL_EVP_UNSUPPORTED'
}
Node.js v18.12.0
Node.jsを18にアップデートした影響だった
Node.js 17からOpenSSLが3.0になったため、3.0で非奨励の処理が差し止められていた。
環境変数でOpenSSLの設定をレガシーに設定すると解消できるとわかった。
export NODE_OPTIONS=--openssl-legacy-provider
Dockerコンテナで環境変数を設定する方法がわからなかったので、
Storybookの起動コマンドに直書きして解消するか確認。
NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6006
(省略)
╭─────────────────────────────────────────────────╮
│ │
│ Storybook 6.5.13 for Vue3 started │
│ 24 s for manager and 31 s for preview │
│ │
│ Local: http://localhost:6006/ │
│ On your network: http://172.22.0.6:6006/ │
│ │
╰─────────────────────────────────────────────────╯
起動できた!
Dockerコンテナの環境変数を設定
Storybookの起動コマンドへNODE_OPTIONS
を残したままにするのは不本意なので、
Dockerコンテナの環境変数が設定したい。
docker-compose.yml
のbuild
に
environment
という環境変数用のオプションがあることがわかった。
ここにNODE_OPTIONS
を設定すると...
build:
environment:
+ NODE_OPTIONS: '--openssl-legacy-provider'
package.jsonのscripts
に直書きしていた環境変数を取り除けた。
"scripts": {
- "storybook": "NODE_OPTIONS=--openssl-legacy-provider start-storybook -p 6006",
+ "storybook": "start-storybook -p 6006",
},
Dockerコンテナで6006ポートを使えるようにする
start-storybook
が成功し起動したのに、
http://localhost:6006がブラウザで「このサイトにアクセスできません」となり表示できない。
Docker環境であらたにポートが使いたいときは設定が必要だった
docker-compose.ymlへ6006
を追加。
build:
ports:
- '${APP_PORT:-80}:80'
- '3000:3000'
+ - '6006:6006'
あらためてStorybookを起動すると、アクセスできた。🎊
stories.tsを開発ソースと同じディレクトリに設置できるようにする
さいしょに、Storybookの設定ファイル/.storybook/main.js
を
/.storybook/main.ts
へ変更しTypeScript化した。
Inertiaの環境では、開発ソースは/resources/views/
配下にあり
ここに置いているコンポーネント名.vue
と同じディレクトリ内へ、コンポーネント名.stories.ts
をならべて設置したいため
main.tsのstories
へ/resources/views/
配下も設定[1]
module.exports = {
stories: [
+ '../resources/views/components/**/*.stories.@(js|jsx|ts|tsx)',
],
storiesを移動して動作確認
前工程の npx sb init ...で生成した/stories
ディレクトリを/resources/views/components/stories
に移動。
Storybookを起動したら、EXAMPLES配下のサンプルが正常に表示されていた。
ここから自作のVueコンポーネントをimportしたstories.tsを作っていく。
自作のstoriesを追加
ためしに、単純なコンポーネントのstoriesを設置してみる。
静的コンテンツだけで構成されたフッター/resources/views/components/footer.vue
にした。
サンプルのHeader.stories.js
を複製し/resources/views/components/footer.stories.ts
を設置。
import LFooter from './footer.vue';
export default {
title: 'Layout/Footer',
component: LFooter,
parameters: {
// More on Story layout: https://storybook.js.org/docs/vue/configure/story-layout
layout: 'fullscreen',
},
};
const Template = () => ({
// Components used in your story `template` are defined in the `components` object
components: { LFooter },
// Then, the spread values can be accessed directly in the template
template: '<l-footer />',
});
export const Default = Template.bind();
追加できた!けれど、スタイルとSVGスプライトが効いていない。(つづく)
-
/resources/views/components
までが、Inertiaのデフォルト設定で設置されるディレクトリ、/resources/views/components
は、このプロジェクトのvueコンポーネント置き場として設置したディレクトリ ↩︎
tsconfigのalias対応をすすめる
開発環境では、tsconfigで@
をルートのresources
へ置き換えるよう設定している。
@/views/components/layouts/footer.vue
↓
/resources/views/components/layouts/footer.vue
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": [
"resources/*"
]
}
},
"include": [
"resources/**/*"
]
}
このままでは自作のVueコンポーネントをimportしたstories.tsでパスが通らないため
Storybookのmain.tsにもaliasを設定する。
この時点で、ためしにコンポーネントのimportをaliasでの参照に書き換えると
Failed to fetch dynamically imported module:
エラーになる。
-import LFooter from './footer.vue';
+import LFooter from '@/views/components/layouts/footer.vue';
storybook-builder-viteでviteの設定を上書きするときはviteFinalを使う
storybook-builder-vite
用のフックviteFinal
で
viteのresolve.aliasに@
のルールを追加した。
+const { mergeConfig } = require('vite');
+const path = require('path');
module.exports = {
stories: [
'../resources/views/components/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/vue3',
core: {
builder: '@storybook/builder-vite',
},
features: {
storyStoreV7: true,
},
+ viteFinal: async (config, { configType }) => {
+ return mergeConfig(config, {
+ resolve: {
+ alias: { '@': path.resolve(__dirname, '../resources') },
+ });
+ },
};
aliasを使ったコンポーネントのimportができるようになったので
スタイルとSVGスプライトが読み込めない問題に対応する。(つづく)
Storybookでスタイルを再現する
/.storybook/preview.ts
は、Viteの起点になっているmain.ts
[1]のような位置づけなので
ここへViteのmain.ts
でimportしていたスタイルシートを追加。
+import 'normalize.css';
+import '@/styles/common.scss';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
};
Sassの中でglob対策
preview.ts
を編集後にStorybokを起動するとエラー発生。
[sass] Can't find stylesheet to import.
╷
12 │ @import '_variable/**/*.scss';
│ ^^^^^^^^^^^^^^^^^^^^^
╵
resources/styles/common.scss 12:9 root stylesheet
プロジェクト本体ではvite.config.ts
でvite-plugin-sass-glob-importでglabを使えるよう設定しているけれど、Storybookにはまだ設定がなく解釈できないことが原因。
import sassGlobImports from 'vite-plugin-sass-glob-import';
export default defineConfig(({ command, mode }) => {
const config: UserConfig = {
plugins: [
sassGlobImports(),
],
};
return config;
});
preview.tsのimportを、ためしにnormalize.css
のみにしたらStorybookは正常に起動した。
globの対応は必要だけど、スタイルシートを参照するところまでは解決できている。
-
/.storybook/main.ts
ではありません、プロジェクト本体のViteの起点ファイルです。(紛らわしい…)
対応中のプロジェクトではInertiaを導入しているため/resources/scripts/main.ts
に設置しています。 ↩︎
vite.config.tsの設定を/.storybook/main.tsに取り込む
/.storybook/main.ts
ではimportで外部ファイルを読み込めないので[1]
loadConfigFromFile
でvite.config.ts
を参照してみる。
+const { mergeConfig, loadConfigFromFile } = require('vite');
-const { mergeConfig } = require('vite');
const path = require('path');
module.exports = {
stories: [
'../resources/views/components/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/vue3',
core: {
builder: '@storybook/builder-vite',
},
features: {
storyStoreV7: true,
},
+ async viteFinal(config, { configType }) {
+ const { config: userConfig } = await loadConfigFromFile(
+ path.resolve(__dirname, '../vite.config.ts')
+ );
+
+ return mergeConfig(config, {
+ ...userConfig,
+ resolve: {
+ alias: { '@': path.resolve(__dirname, '../resources') },
+ },
+ plugins: [],
+ });
+ },
- viteFinal: async (config, { configType }) => {
- return mergeConfig(config, {
- resolve: {
- alias: { '@': path.resolve(__dirname, '../resources') },
- });
- },
};
が、Sass内のglobを認識できないエラーは継続されている。
この設定ではプラグインは効いていなかった。(つづく)
-
vite.config.ts
では、プラグインをimportしてから設定している。 ↩︎