2020-04-21 storybook-preset-nuxt を作りたかった話
背景
NuxtJS と Storybook を併用していると、nuxt.config.ts と .storybook/main.js の内容の同期が面倒になる。
Storybook には presets と呼ばれる仕組みがあり、.storybook/main.js の一部を別のファイルに切り出すことができる
公式の presets としては @storybook/preset-typescript や @storybook/preset-scss などが提供されている。
今回挑戦したのは、これの NuxtJS 版である。NuxtJS の 2.12.0 では webpack の config を dump する機能が追加された。
これを用いて dump した webpack の config を、Storybook に渡してやれば、Storybook 用の webpack をメンテすることなく、済むのでは?と思いついたのがモチベーションである。
試したこと
以下のコードを用意し、 .storybook/main.js の presets でロードするようにした。
code:nuxt-preset.js
const path = require("path")
const { getWebpackConfig } = require("nuxt")
/**
*
* @param {import('webpack').Configuration} webpackConfig
* @returns {Promise<import('webpack').Configuration>}
*/
async function processConfig(webpackConfig = {}) {
/**
* @type {import('webpack').Configuration}
*/
const nuxtWebpackConfig = await getWebpackConfig();
const { resolve = {}, plugins = [], module } = webpackConfig;
return {
...webpackConfig,
module: {
...module,
rules: nuxtWebpackConfig.module.rules,
},
plugins: [
...plugins,
...nuxtWebpackConfig.plugins
],
resolve: {
...resolve,
...nuxtWebpackConfig.resolve
},
}
}
module.exports = {
webpackFinal: async (webpackConfig = {}) => {
const config = await processConfig(webpackConfig)
return config;
}
}
発生したこと
yarn start-storybook を実行したところ、以下のエラーが得られた。
code:error.log
ERR! at VueLoaderPlugin.apply (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/vue-loader/lib/plugin-webpack4.js:46:13)
ERR! at webpack (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/webpack/lib/webpack.js:51:13)
ERR! at /Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/dev-server.js:116:50
ERR! at async Promise.all (index 1)
ERR! at async buildDevStandalone (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:343:9)
ERR! at async buildDev (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:415:3)
ERR! at VueLoaderPlugin.apply (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/vue-loader/lib/plugin-webpack4.js:46:13)
ERR! at webpack (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/webpack/lib/webpack.js:51:13)
ERR! at /Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/dev-server.js:116:50
ERR! at async Promise.all (index 1)
ERR! at async buildDevStandalone (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:343:9)
ERR! at async buildDev (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:415:3) {
ERR! stack: 'Error: VueLoaderPlugin Error vue-loader 15 currently does not support vue rules with oneOf.\n' + ERR! ' at VueLoaderPlugin.apply (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/vue-loader/lib/plugin-webpack4.js:46:13)\n' +
ERR! ' at webpack (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/webpack/lib/webpack.js:51:13)\n' +
ERR! ' at /Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/dev-server.js:116:50\n' +
ERR! ' at async Promise.all (index 1)\n' +
ERR! ' at async buildDevStandalone (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:343:9)\n' +
ERR! ' at async buildDev (/Users/odan/source/github.com/odan-sandbox/nuxtjs-storybook-sandbox/node_modules/@storybook/core/dist/server/build-dev.js:415:3)'
ERR! }
内部の挙動を確かめたところ、pug-loader の oneOf に対してエラーが throw されていることがわかった。
問題の切り分け
webpack で build 可能か試す
以下の webpack.config.js を用意して、webpack-cli を実行した。その結果 build は成功した。
code:webpack.config.js
const { getWebpackConfig } = require('nuxt')
module.exports = getWebpackConfig()
@storybook/vue を使わない
start-storybook コマンドの実態は @storybook/vue の bin である。この bin は以下のファイルの内容を読み込み、@storybook/core/server の buildDev 関数を実行している。
buildDev に直接、NuxtJS が dump した webpack config を渡すとどうなるかを確かめた。
code:build.js
const { buildDev } = require('@storybook/core/server')
const { getWebpackConfig } = require('nuxt')
async function main() {
const webpack = await getWebpackConfig()
await buildDev({
packageJson: {
version: '1.0'
}
})
}
main()
実行した結果、Error: Cannot find module 'client' や Error: Can't resolve '@storybook/undefined' というエラーが出て、build が成功しなかった。
結論
Storybook 何もわからん