Skip to content

Commit

Permalink
feat: compatible with webpack5 addons (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
fi3ework authored Oct 2, 2024
1 parent 548edb9 commit a5108ac
Show file tree
Hide file tree
Showing 50 changed files with 4,469 additions and 248 deletions.
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,28 @@ The `configType` variable will be either `"DEVELOPMENT"` or `"PRODUCTION"`.
The function should return the updated Rsbuild configuration.
### Using customized addon
Since Rspack is compatible with Webpack 5, storybook-builder-rsbuild can also use Webpack 5 addons. The configuration for ⁠`webpackAddons` is identical to that of Storybook's [addons](https://storybook.js.org/docs/api/main-config/main-config-addons). However, Storybook's addons only support the Vite builder and Webpack 5 builder by default. If you want to use Webpack 5 addons in storybook-builder-rsbuild, please add them to ⁠webpackAddons. For example, using the [`@storybook/addon-coverage`](https://github.com/storybookjs/addon-coverage) addon:
```js
const config: StorybookConfig = {
// --snip--
webpackAddons: [
{
name: '@storybook/addon-coverage',
options: {
istanbul: {
include: ['src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
exclude: [],
},
},
},
],
// --snip--
}
```
## FAQ
### How to Storybook to a subdirectory / subpath?
Expand Down
1 change: 0 additions & 1 deletion packages/builder-rsbuild/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
"@types/fs-extra": "^11.0.4",
"@types/node": "^18.0.0",
"@types/pretty-hrtime": "^1.0.3",
"add": "^2.0.6",
"pretty-hrtime": "^1.0.3",
"slash": "^5.1.0",
"storybook": "8.4.0-alpha.0",
Expand Down
57 changes: 53 additions & 4 deletions packages/builder-rsbuild/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@ import express from 'express'
import fs from 'fs-extra'
import prettyTime from 'pretty-hrtime'
import { corePath } from 'storybook/core-path'
import { getPresets, resolveAddonName } from 'storybook/internal/common'
import { WebpackInvocationError } from 'storybook/internal/server-errors'
import type { Options } from 'storybook/internal/types'
import type {
Options,
Preset,
StorybookConfigRaw,
} from 'storybook/internal/types'
import rsbuildConfig, {
type RsbuildBuilderOptions,
} from './preview/iframe-rsbuild.config'
Expand Down Expand Up @@ -43,10 +48,53 @@ export const executor = {
},
}

export const rsbuild = async (_: unknown, options: RsbuildBuilderOptions) => {
const isObject = (val: unknown): val is Record<string, any> =>
val != null && typeof val === 'object' && Array.isArray(val) === false

function nonNullables<T>(value: T): value is NonNullable<T> {
return value !== undefined
}

const rsbuild = async (_: unknown, options: RsbuildBuilderOptions) => {
const { presets } = options
let defaultConfig = await rsbuildConfig(options)
// #region webpack addons
const webpackAddons =
await presets.apply<StorybookConfigRaw['addons']>('webpackAddons')
const resolvedWebpackAddons = (webpackAddons ?? [])
.map((preset: Preset) => {
const options = isObject(preset) ? preset.options || undefined : undefined
const name = isObject(preset) ? preset.name : preset
// Taken fromm https://github.com/storybookjs/storybook/blob/f3b15ce1f28daac195e7698c075be7790f8172f1/code/core/src/common/presets.ts#L198.
return resolveAddonName(options.configDir, name, options)
})
.filter(nonNullables)
const { apply } = await getPresets(resolvedWebpackAddons, options)
const webpackAddonsConfig: rsbuildReal.Rspack.Configuration = await apply(
'webpackFinal',
// TODO: using empty webpack config as base for now. It's better to using the composed rspack
// config in `iframe-rsbuild.config.ts` as base config. But when `tools.rspack` is an async function,
// the following `tools.rspack` raise an ` Promises are not supported` error.
{
output: {},
module: {},
plugins: [],
resolve: {},
devServer: {},
optimization: {},
performance: {},
externals: {},
experiments: {},
node: {},
stats: {},
entry: {},
},
options,
)
// #endregion

let defaultConfig = await rsbuildConfig(options, webpackAddonsConfig)
const shimsConfig = await applyReactShims(defaultConfig, options)

defaultConfig = mergeRsbuildConfig(
defaultConfig,
shimsConfig,
Expand All @@ -58,13 +106,14 @@ export const rsbuild = async (_: unknown, options: RsbuildBuilderOptions) => {
options,
)

return mergeRsbuildConfig(finalDefaultConfig)
return finalDefaultConfig
}

export const getConfig: RsbuildBuilder['getConfig'] = async (options) => {
const { presets } = options
const typescriptOptions = await presets.apply('typescript', {}, options)
const frameworkOptions = await presets.apply<any>('frameworkOptions')

return rsbuild({}, {
...options,
typescriptOptions,
Expand Down
10 changes: 5 additions & 5 deletions packages/builder-rsbuild/src/preview/iframe-rsbuild.config.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { dirname, join, resolve } from 'node:path'
import { loadConfig, mergeRsbuildConfig } from '@rsbuild/core'
import type { RsbuildConfig } from '@rsbuild/core'
import type { RsbuildConfig, Rspack } from '@rsbuild/core'
import { pluginTypeCheck } from '@rsbuild/plugin-type-check'
import { webpack as docsWebpack } from '@storybook/addon-docs/dist/preset'
// @ts-expect-error (I removed this on purpose, because it's incorrect)
Expand Down Expand Up @@ -56,6 +56,7 @@ export type RsbuildBuilderOptions = Options & {

export default async (
options: RsbuildBuilderOptions,
extraWebpackConfig?: Rspack.Configuration,
): Promise<RsbuildConfig> => {
const { rsbuildConfigPath, addonDocs } =
await getBuilderOptions<BuilderOptions>(options)
Expand Down Expand Up @@ -199,7 +200,7 @@ export default async (
? 'static/media/[name].[contenthash:8][ext]'
: 'static/media/[path][name][ext]'

const merged = mergeRsbuildConfig(contentFromConfig, {
const rsbuildConfig = mergeRsbuildConfig(contentFromConfig, {
output: {
cleanDistPath: false,
assetPrefix: '/',
Expand Down Expand Up @@ -354,8 +355,7 @@ export default async (
// as it's a built-in logic for Storybook's official webpack and Vite builder.
// we should remove this once we merge this into Storybook's repository
// by defining builder plugin in @storybook/addon-docs/preset's source code

return mergeConfig(config, appliedDocsWebpack)
return mergeConfig(config, extraWebpackConfig, appliedDocsWebpack)
},
htmlPlugin: {
filename: 'iframe.html',
Expand Down Expand Up @@ -391,5 +391,5 @@ export default async (
},
})

return merged
return rsbuildConfig
}
2 changes: 2 additions & 0 deletions packages/builder-rsbuild/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
Builder,
BuilderResult as BuilderResultBase,
Options,
StorybookConfigRaw,
TypescriptOptions as TypeScriptOptionsBase,
} from 'storybook/internal/types'
import type { Stats } from './index'
Expand Down Expand Up @@ -32,6 +33,7 @@ export type RsbuildFinal = (

export type StorybookConfigRsbuild = {
rsbuildFinal?: RsbuildFinal
webpackAddons?: StorybookConfigRaw['addons']
}

export type BuilderOptions = {
Expand Down
1 change: 0 additions & 1 deletion packages/react-rsbuild/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
"@rsbuild/core": "1.0.8",
"@storybook/types": "8.4.0-alpha.0",
"@types/resolve": "^1.20.6",
"add": "^2.0.6",
"react": "18.3.1",
"react-dom": "18.3.1",
"storybook": "8.4.0-alpha.0",
Expand Down
1 change: 0 additions & 1 deletion packages/react-rsbuild/src/preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const rsbuildFinal: StorybookConfig['rsbuildFinal'] = async (

export const core: PresetProperty<'core'> = async (config, options) => {
const framework = await options.presets.apply('framework')

return {
...config,
builder: {
Expand Down
Loading

0 comments on commit a5108ac

Please sign in to comment.