@modern-js/storybook-builder 0.0.0-next-20230913035856
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +7 -0
- package/.turbo/turbo-build.log +6 -0
- package/CHANGELOG.md +24 -0
- package/LICENSE +21 -0
- package/dist/cjs/addons/components/modern.js +65 -0
- package/dist/cjs/addons/constants.js +11 -0
- package/dist/cjs/addons/index.js +20 -0
- package/dist/cjs/addons/preset/preview.js +14 -0
- package/dist/cjs/addons/type.js +4 -0
- package/dist/cjs/addons/withPluginRuntime.js +20 -0
- package/dist/cjs/build.js +109 -0
- package/dist/cjs/core.js +40 -0
- package/dist/cjs/docgen/actualNameHandler.js +34 -0
- package/dist/cjs/docgen/index.js +74 -0
- package/dist/cjs/docgen/loader.js +37 -0
- package/dist/cjs/docgen/process.js +39 -0
- package/dist/cjs/index.js +35 -0
- package/dist/cjs/plugin-storybook.js +316 -0
- package/dist/cjs/preset.js +61 -0
- package/dist/cjs/types.js +11 -0
- package/dist/cjs/utils.js +142 -0
- package/dist/esm/addons/components/modern.js +44 -0
- package/dist/esm/addons/constants.js +1 -0
- package/dist/esm/addons/index.js +5 -0
- package/dist/esm/addons/preset/preview.js +4 -0
- package/dist/esm/addons/type.js +1 -0
- package/dist/esm/addons/withPluginRuntime.js +10 -0
- package/dist/esm/build.js +83 -0
- package/dist/esm/core.js +30 -0
- package/dist/esm/docgen/actualNameHandler.js +24 -0
- package/dist/esm/docgen/index.js +54 -0
- package/dist/esm/docgen/loader.js +26 -0
- package/dist/esm/docgen/process.js +28 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/plugin-storybook.js +296 -0
- package/dist/esm/preset.js +36 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/utils.js +95 -0
- package/dist/types/addons/components/modern.d.ts +5 -0
- package/dist/types/addons/constants.d.ts +1 -0
- package/dist/types/addons/index.d.ts +2 -0
- package/dist/types/addons/preset/preview.d.ts +1 -0
- package/dist/types/addons/type.d.ts +4 -0
- package/dist/types/addons/withPluginRuntime.d.ts +2 -0
- package/dist/types/build.d.ts +7 -0
- package/dist/types/core.d.ts +4 -0
- package/dist/types/docgen/actualNameHandler.d.ts +14 -0
- package/dist/types/docgen/index.d.ts +9 -0
- package/dist/types/docgen/loader.d.ts +2 -0
- package/dist/types/docgen/process.d.ts +10 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/plugin-storybook.d.ts +6 -0
- package/dist/types/preset.d.ts +6 -0
- package/dist/types/types.d.ts +15 -0
- package/dist/types/utils.d.ts +12 -0
- package/index.js +24 -0
- package/modern.config.js +5 -0
- package/package.json +96 -0
- package/src/addons/components/modern.tsx +52 -0
- package/src/addons/constants.ts +1 -0
- package/src/addons/index.ts +8 -0
- package/src/addons/preset/preview.ts +3 -0
- package/src/addons/type.ts +4 -0
- package/src/addons/withPluginRuntime.ts +18 -0
- package/src/build.ts +119 -0
- package/src/core.ts +51 -0
- package/src/docgen/actualNameHandler.ts +57 -0
- package/src/docgen/index.ts +100 -0
- package/src/docgen/loader.ts +34 -0
- package/src/docgen/process.ts +44 -0
- package/src/index.ts +7 -0
- package/src/plugin-storybook.ts +462 -0
- package/src/preset.ts +59 -0
- package/src/types.ts +21 -0
- package/src/utils.ts +131 -0
- package/templates/preview.ejs +54 -0
- package/templates/virtualModuleModernEntry.js.handlebars +43 -0
- package/tsconfig.json +16 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
import { BuilderPlugin } from '@modern-js/builder-shared';
|
2
|
+
import type { Options } from '@storybook/types';
|
3
|
+
import type { BuilderPluginAPI as WebpackAPI } from '@modern-js/builder-webpack-provider';
|
4
|
+
import type { BuilderPluginAPI as RspackAPI } from '@modern-js/builder-rspack-provider';
|
5
|
+
export declare function finalize(): Promise<void>;
|
6
|
+
export declare const pluginStorybook: (cwd: string, options: Options) => BuilderPlugin<WebpackAPI | RspackAPI>;
|
@@ -0,0 +1,6 @@
|
|
1
|
+
import type { Options } from '@storybook/types';
|
2
|
+
import { BuilderConfig } from './types';
|
3
|
+
export declare const previewMainTemplate: () => string;
|
4
|
+
export declare const entries: (_: unknown, options: Options) => Promise<string[]>;
|
5
|
+
export declare const modern: (builderConfig: BuilderConfig, options: Options) => BuilderConfig;
|
6
|
+
export { decorators } from './addons/preset/preview';
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import type { BuilderConfig as WebpackBuilderConfig } from '@modern-js/builder-webpack-provider';
|
2
|
+
import type { BuilderConfig as RspackBuilderConfig } from '@modern-js/builder-rspack-provider';
|
3
|
+
import { BuilderPlugin } from '@modern-js/builder-shared';
|
4
|
+
export type BundlerType = 'webpack' | 'rspack';
|
5
|
+
export type { WebpackBuilderConfig, RspackBuilderConfig };
|
6
|
+
export type AllBuilderConfig = WebpackBuilderConfig | RspackBuilderConfig;
|
7
|
+
export type FrameworkOptions = {
|
8
|
+
bundler?: BundlerType;
|
9
|
+
builderConfig?: AllBuilderConfig;
|
10
|
+
configPath?: string;
|
11
|
+
};
|
12
|
+
export type BuilderConfig = AllBuilderConfig & {
|
13
|
+
builderPlugins?: BuilderPlugin[];
|
14
|
+
};
|
15
|
+
export { defineConfig } from '@modern-js/builder/cli';
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { AllBuilderConfig } from './types';
|
2
|
+
export declare const VIRTUAL_MODULE_BASE = ".MODERN_STORYBOOK";
|
3
|
+
export declare const STORIES_FILENAME = "storybook-stories.js";
|
4
|
+
export declare const STORYBOOK_CONFIG_ENTRY = "storybook-config-entry.js";
|
5
|
+
export declare const requireResolve: (importer: string, path: string) => void;
|
6
|
+
export declare function getProvider(bundler: 'webpack' | 'rspack', builderConfig: AllBuilderConfig): Promise<import("@modern-js/builder-webpack-provider").BuilderWebpackProvider | import("@modern-js/builder-rspack-provider").BuilderRspackProvider | undefined>;
|
7
|
+
export declare function virtualModule(tempDir: string, cwd: string, virtualModuleMap: Record<string, string>): Promise<[Record<string, string>, (p: string, content: string) => void]>;
|
8
|
+
export declare function toImportFn(cwd: string, stories: string[]): Promise<string>;
|
9
|
+
export declare function getAbsolutePath<I extends string>(input: I): I;
|
10
|
+
export declare function maybeGetAbsolutePath<I extends string>(input: I): I | false;
|
11
|
+
export declare function runWithErrorMsg<T>(op: () => Promise<T>, msg: string): Promise<T | undefined>;
|
12
|
+
export declare function isDev(): boolean;
|
package/index.js
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
/**
|
2
|
+
* storybook uses import() to load this package.
|
3
|
+
* and directly use the result.start, however
|
4
|
+
* our exports are transpiled to something like
|
5
|
+
*
|
6
|
+
* ```
|
7
|
+
* Object.defineProperty(exports, 'start', {
|
8
|
+
* get() { return ... }
|
9
|
+
* })
|
10
|
+
* ```
|
11
|
+
*
|
12
|
+
* we need to annotate the export, so it can be linked during compile time
|
13
|
+
*/
|
14
|
+
module.exports = require('./dist/cjs');
|
15
|
+
|
16
|
+
// eslint-disable-next-line no-constant-condition
|
17
|
+
if (false) {
|
18
|
+
exports.start = null;
|
19
|
+
exports.build = null;
|
20
|
+
exports.bail = null;
|
21
|
+
exports.getConfig = null;
|
22
|
+
exports.corePresets = null;
|
23
|
+
exports.defineConfig = null;
|
24
|
+
}
|
package/modern.config.js
ADDED
package/package.json
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
{
|
2
|
+
"name": "@modern-js/storybook-builder",
|
3
|
+
"version": "0.0.0-next-20230913035856",
|
4
|
+
"description": "modern.js support for storybook",
|
5
|
+
"repository": {
|
6
|
+
"type": "git",
|
7
|
+
"url": "https://github.com/web-infra-dev/modern.js",
|
8
|
+
"directory": "packages/storybook/builder"
|
9
|
+
},
|
10
|
+
"jsnext:source": "./src/index.ts",
|
11
|
+
"main": "./index.js",
|
12
|
+
"types": "./dist/index.d.ts",
|
13
|
+
"exports": {
|
14
|
+
".": {
|
15
|
+
"jsnext:source": "./src/index.ts",
|
16
|
+
"types": "./dist/types/index.d.ts",
|
17
|
+
"default": "./index.js"
|
18
|
+
},
|
19
|
+
"./preset": "./dist/esm/preset.js",
|
20
|
+
"./types": {
|
21
|
+
"jsnext:source": "./src/types.ts",
|
22
|
+
"types": "./dist/types/types.d.ts",
|
23
|
+
"default": "./dist/cjs/types.js"
|
24
|
+
},
|
25
|
+
"./templates/preview.ejs": "./templates/preview.ejs",
|
26
|
+
"./templates/virtualModuleModernEntry.js.handlebars": "./templates/virtualModuleModernEntry.js.handlebars",
|
27
|
+
"./package.json": "./package.json"
|
28
|
+
},
|
29
|
+
"engines": {
|
30
|
+
"node": ">=16.0.0"
|
31
|
+
},
|
32
|
+
"keywords": [],
|
33
|
+
"author": "",
|
34
|
+
"license": "MIT",
|
35
|
+
"dependencies": {
|
36
|
+
"@rspack/dev-client": "0.3.2",
|
37
|
+
"@storybook/components": "^7.4.0",
|
38
|
+
"@storybook/core-common": "^7.4.0",
|
39
|
+
"@storybook/csf-plugin": "^7.4.0",
|
40
|
+
"@storybook/global": "^5.0.0",
|
41
|
+
"@storybook/mdx1-csf": "^1.0.0",
|
42
|
+
"@storybook/mdx2-csf": "^1.1.0",
|
43
|
+
"@storybook/preview": "^7.4.0",
|
44
|
+
"@storybook/preview-api": "^7.4.0",
|
45
|
+
"@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0",
|
46
|
+
"@storybook/router": "^7.4.0",
|
47
|
+
"@storybook/theming": "^7.4.0",
|
48
|
+
"@swc/helpers": "0.5.1",
|
49
|
+
"ast-types": "^0.14.2",
|
50
|
+
"minimatch": "^9.0.3",
|
51
|
+
"react-docgen": "6.0.0-alpha.3",
|
52
|
+
"remark-external-links": "^9.0.1",
|
53
|
+
"remark-slug": "^7.0.1",
|
54
|
+
"serve-static": "^1.14.1",
|
55
|
+
"tinypool": "^0.8.0",
|
56
|
+
"webpack-hot-middleware": "^2.25.4",
|
57
|
+
"@modern-js/builder": "0.0.0-next-20230913035856",
|
58
|
+
"@modern-js/utils": "0.0.0-next-20230913035856",
|
59
|
+
"@modern-js/builder-shared": "0.0.0-next-20230913035856",
|
60
|
+
"@modern-js/core": "0.0.0-next-20230913035856",
|
61
|
+
"@modern-js/runtime": "0.0.0-next-20230913035856"
|
62
|
+
},
|
63
|
+
"devDependencies": {
|
64
|
+
"@storybook/types": "^7.4.0",
|
65
|
+
"@types/babel__core": "^7.20.1",
|
66
|
+
"@types/serve-static": "^1.13.10",
|
67
|
+
"@types/webpack-hot-middleware": "^2.25.6",
|
68
|
+
"typescript": "^5.2.2",
|
69
|
+
"@modern-js/builder-rspack-provider": "0.0.0-next-20230913035856",
|
70
|
+
"@modern-js/builder-webpack-provider": "0.0.0-next-20230913035856",
|
71
|
+
"@modern-js/core": "0.0.0-next-20230913035856",
|
72
|
+
"@scripts/build": "0.0.0-next-20230913035856"
|
73
|
+
},
|
74
|
+
"peerDependencies": {
|
75
|
+
"@modern-js/builder-rspack-provider": "0.0.0-next-20230913035856",
|
76
|
+
"@modern-js/builder-webpack-provider": "0.0.0-next-20230913035856"
|
77
|
+
},
|
78
|
+
"peerDependenciesMeta": {
|
79
|
+
"@modern-js/builder-rspack-provider": {
|
80
|
+
"optional": true
|
81
|
+
},
|
82
|
+
"@modern-js/builder-webpack-provider": {
|
83
|
+
"optional": true
|
84
|
+
}
|
85
|
+
},
|
86
|
+
"publishConfig": {
|
87
|
+
"registry": "https://registry.npmjs.org/",
|
88
|
+
"access": "public",
|
89
|
+
"provenance": true
|
90
|
+
},
|
91
|
+
"scripts": {
|
92
|
+
"build": "modern-lib build",
|
93
|
+
"dev": "modern-lib build --watch",
|
94
|
+
"test": "vitest run"
|
95
|
+
}
|
96
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import { createApp } from '@modern-js/runtime';
|
3
|
+
import type { Plugin, RouterConfig } from '@modern-js/runtime';
|
4
|
+
import router from '@modern-js/runtime/router';
|
5
|
+
import state from '@modern-js/runtime/model';
|
6
|
+
import type { IConfig } from '../type';
|
7
|
+
|
8
|
+
export const WrapProviders = (storyFn: any, config: IConfig) => {
|
9
|
+
const App = createApp({
|
10
|
+
plugins: resolvePlugins(config.modernConfigRuntime),
|
11
|
+
})(storyFn);
|
12
|
+
|
13
|
+
return <App />;
|
14
|
+
};
|
15
|
+
|
16
|
+
const allowedRuntimeAPI = {
|
17
|
+
router: 'router',
|
18
|
+
state: 'state',
|
19
|
+
};
|
20
|
+
const allowedRuntimeAPIValues = Object.values(allowedRuntimeAPI);
|
21
|
+
|
22
|
+
export const resolvePlugins = (runtime: IConfig['modernConfigRuntime']) => {
|
23
|
+
const plugins: Plugin[] = [];
|
24
|
+
|
25
|
+
if (!runtime) {
|
26
|
+
return plugins;
|
27
|
+
}
|
28
|
+
|
29
|
+
Object.keys(runtime).forEach(api => {
|
30
|
+
if (allowedRuntimeAPIValues.includes(api)) {
|
31
|
+
if (api === allowedRuntimeAPI.state) {
|
32
|
+
if (typeof runtime.state === 'boolean') {
|
33
|
+
if (runtime.state) {
|
34
|
+
plugins.push(state({}));
|
35
|
+
}
|
36
|
+
} else if (typeof runtime.state === 'object') {
|
37
|
+
plugins.push(state(runtime.state));
|
38
|
+
}
|
39
|
+
} else if (api === allowedRuntimeAPI.router) {
|
40
|
+
// TODO: React Router v6 is not supported yet
|
41
|
+
plugins.push(
|
42
|
+
router({
|
43
|
+
...{ serverBase: ['/'] },
|
44
|
+
...(runtime.router as RouterConfig),
|
45
|
+
}),
|
46
|
+
);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
});
|
50
|
+
|
51
|
+
return plugins;
|
52
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
export const ADDON_ID = 'storybook/modern-runtime';
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { useParameter } from '@storybook/preview-api';
|
2
|
+
import { DecoratorFunction } from '@storybook/types';
|
3
|
+
import { WrapProviders } from './components/modern';
|
4
|
+
import type { IConfig } from './type';
|
5
|
+
|
6
|
+
export const withPluginRuntime: DecoratorFunction = storyFn => {
|
7
|
+
const modernConfigRuntime = useParameter<IConfig['modernConfigRuntime']>(
|
8
|
+
'modernConfigRuntime',
|
9
|
+
);
|
10
|
+
const modernConfigDesignToken = useParameter<
|
11
|
+
IConfig['modernConfigDesignToken']
|
12
|
+
>('modernConfigDesignToken');
|
13
|
+
|
14
|
+
return WrapProviders(storyFn, {
|
15
|
+
modernConfigRuntime: modernConfigRuntime || {},
|
16
|
+
modernConfigDesignToken,
|
17
|
+
});
|
18
|
+
};
|
package/src/build.ts
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
import { dirname, join, parse } from 'path';
|
2
|
+
import webpackDevMiddleware from '@modern-js/utils/webpack-dev-middleware';
|
3
|
+
import webpackHotMiddleware from 'webpack-hot-middleware';
|
4
|
+
import serveStatic from 'serve-static';
|
5
|
+
import type { Builder as RawStorybookBuilder, Stats } from '@storybook/types';
|
6
|
+
import { fs } from '@modern-js/utils';
|
7
|
+
import type { FrameworkOptions } from './types';
|
8
|
+
import { getCompiler } from './core';
|
9
|
+
import { finalize } from './plugin-storybook';
|
10
|
+
|
11
|
+
export type StorybookBuilder = RawStorybookBuilder<FrameworkOptions, Stats>;
|
12
|
+
|
13
|
+
export const getConfig: StorybookBuilder['getConfig'] = async options => {
|
14
|
+
const { presets } = options;
|
15
|
+
|
16
|
+
const frameworkOptions: {
|
17
|
+
name: string;
|
18
|
+
options: FrameworkOptions;
|
19
|
+
} = await presets.apply('frameworkOptions');
|
20
|
+
|
21
|
+
return frameworkOptions?.options || {};
|
22
|
+
};
|
23
|
+
|
24
|
+
// export `build` is used by storybook core
|
25
|
+
export const build: StorybookBuilder['build'] = async ({ options }) => {
|
26
|
+
const config = await getConfig(options);
|
27
|
+
|
28
|
+
const compiler = await getCompiler(process.cwd(), config, options);
|
29
|
+
|
30
|
+
const previewResolvedDir = dirname(
|
31
|
+
require.resolve('@storybook/preview/package.json'),
|
32
|
+
);
|
33
|
+
const previewDirOrigin = join(previewResolvedDir, 'dist');
|
34
|
+
const previewDirTarget = join(options.outputDir || '', `sb-preview`);
|
35
|
+
|
36
|
+
const previewFiles = fs.copy(previewDirOrigin, previewDirTarget, {
|
37
|
+
filter: src => {
|
38
|
+
const { ext } = parse(src);
|
39
|
+
if (ext) {
|
40
|
+
return ext === '.js';
|
41
|
+
}
|
42
|
+
return true;
|
43
|
+
},
|
44
|
+
});
|
45
|
+
|
46
|
+
const compilation: Promise<Stats> = new Promise((resolve, reject) => {
|
47
|
+
compiler.run((err, stats) => {
|
48
|
+
if (err) {
|
49
|
+
reject(err);
|
50
|
+
} else {
|
51
|
+
resolve(stats as Stats);
|
52
|
+
}
|
53
|
+
});
|
54
|
+
});
|
55
|
+
|
56
|
+
const [stats] = await Promise.all([compilation, previewFiles]);
|
57
|
+
|
58
|
+
return stats;
|
59
|
+
};
|
60
|
+
|
61
|
+
// export `start` is used by storybook core
|
62
|
+
export const start: StorybookBuilder['start'] = async ({
|
63
|
+
options,
|
64
|
+
router,
|
65
|
+
startTime,
|
66
|
+
}) => {
|
67
|
+
const previewResolvedDir = dirname(
|
68
|
+
require.resolve('@storybook/preview/package.json'),
|
69
|
+
);
|
70
|
+
const previewDirOrigin = join(previewResolvedDir, 'dist');
|
71
|
+
|
72
|
+
router.use(
|
73
|
+
`/sb-preview`,
|
74
|
+
serveStatic(previewDirOrigin, { immutable: true, maxAge: '5m' }),
|
75
|
+
);
|
76
|
+
|
77
|
+
const config = await getConfig(options);
|
78
|
+
|
79
|
+
const compiler = await getCompiler(process.cwd(), config, options);
|
80
|
+
|
81
|
+
const middleware = webpackDevMiddleware(compiler, {
|
82
|
+
writeToDisk:
|
83
|
+
// @ts-expect-error
|
84
|
+
config.builderConfig?.tools?.devServer?.devMiddleware?.writeToDisk ||
|
85
|
+
true,
|
86
|
+
|
87
|
+
// builder can log errors, so not using dev-middleware logs
|
88
|
+
stats: false,
|
89
|
+
});
|
90
|
+
|
91
|
+
router.use(middleware);
|
92
|
+
router.use(webpackHotMiddleware(compiler, { log: false }));
|
93
|
+
|
94
|
+
const stats: Stats = await new Promise(resolve => {
|
95
|
+
middleware.waitUntilValid(stats => {
|
96
|
+
resolve(stats as Stats);
|
97
|
+
});
|
98
|
+
});
|
99
|
+
|
100
|
+
if (!stats) {
|
101
|
+
throw new Error('build failed');
|
102
|
+
}
|
103
|
+
|
104
|
+
const statsJson = stats.toJson();
|
105
|
+
|
106
|
+
if (statsJson.errors.length > 1) {
|
107
|
+
throw stats;
|
108
|
+
}
|
109
|
+
|
110
|
+
return {
|
111
|
+
bail,
|
112
|
+
stats,
|
113
|
+
totalTime: process.hrtime(startTime),
|
114
|
+
};
|
115
|
+
};
|
116
|
+
|
117
|
+
export const bail = async () => {
|
118
|
+
await finalize();
|
119
|
+
};
|
package/src/core.ts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
import { createBuilder, mergeBuilderConfig } from '@modern-js/builder';
|
2
|
+
import { loadConfig } from '@modern-js/core';
|
3
|
+
import type { Options } from '@storybook/types';
|
4
|
+
import type { Compiler } from '@modern-js/utils/webpack-dev-middleware';
|
5
|
+
import type { BuilderConfig, FrameworkOptions } from './types';
|
6
|
+
import { getProvider, runWithErrorMsg } from './utils';
|
7
|
+
import { pluginStorybook } from './plugin-storybook';
|
8
|
+
|
9
|
+
export async function getCompiler(
|
10
|
+
cwd: string,
|
11
|
+
frameworkConfig: FrameworkOptions,
|
12
|
+
options: Options,
|
13
|
+
): Promise<Compiler> {
|
14
|
+
const bundler = frameworkConfig.bundler || 'webpack';
|
15
|
+
|
16
|
+
const { presets } = options;
|
17
|
+
const entries = await presets.apply<string[]>('entries', []);
|
18
|
+
|
19
|
+
const res = await runWithErrorMsg(
|
20
|
+
() => loadConfig(cwd, frameworkConfig.configPath || 'modern.config.ts'),
|
21
|
+
'Failed to load config',
|
22
|
+
);
|
23
|
+
const loadedConfig = (res ? res.config : {}) as BuilderConfig;
|
24
|
+
|
25
|
+
const otherBuilderConfig =
|
26
|
+
(await presets.apply<BuilderConfig | void>('modern', loadedConfig)) || {};
|
27
|
+
|
28
|
+
const builderConfig = mergeBuilderConfig(otherBuilderConfig, loadedConfig);
|
29
|
+
|
30
|
+
const provider = await getProvider(bundler, builderConfig);
|
31
|
+
|
32
|
+
if (!provider) {
|
33
|
+
throw new Error(`@modern-js/builder-${bundler}-provider not found `);
|
34
|
+
}
|
35
|
+
|
36
|
+
const builder = await createBuilder(provider, {
|
37
|
+
cwd,
|
38
|
+
target: 'web',
|
39
|
+
framework: 'modern.js storybook',
|
40
|
+
entry: {
|
41
|
+
main: entries,
|
42
|
+
},
|
43
|
+
});
|
44
|
+
|
45
|
+
builder.addPlugins([
|
46
|
+
pluginStorybook(cwd, options),
|
47
|
+
...(loadedConfig.builderPlugins || []),
|
48
|
+
]);
|
49
|
+
|
50
|
+
return builder.createCompiler() as Promise<Compiler>;
|
51
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/**
|
2
|
+
* This is heavily based on the react-docgen `displayNameHandler`
|
3
|
+
* (https://github.com/reactjs/react-docgen/blob/26c90c0dd105bf83499a83826f2a6ff7a724620d/src/handlers/displayNameHandler.ts)
|
4
|
+
* but instead defines an `actualName` property on the generated docs that is taken first from the component's actual name.
|
5
|
+
* This addresses an issue where the name that the generated docs are stored under is incorrectly named with the `displayName`
|
6
|
+
* and not the component's actual name.
|
7
|
+
*
|
8
|
+
* This is inspired by `actualNameHandler` from https://github.com/storybookjs/babel-plugin-react-docgen, but is modified
|
9
|
+
* directly from displayNameHandler, using the same approach as babel-plugin-react-docgen.
|
10
|
+
*/
|
11
|
+
|
12
|
+
import { namedTypes as t } from 'ast-types';
|
13
|
+
import type { NodePath } from 'ast-types/lib/node-path';
|
14
|
+
import { getNameOrValue, isReactForwardRefCall } from 'react-docgen/dist/utils';
|
15
|
+
import type { Importer } from 'react-docgen/dist/parse';
|
16
|
+
import type Documentation from 'react-docgen/dist/Documentation';
|
17
|
+
|
18
|
+
export default function actualNameHandler(
|
19
|
+
documentation: Documentation,
|
20
|
+
path: NodePath,
|
21
|
+
importer: Importer,
|
22
|
+
): void {
|
23
|
+
if (
|
24
|
+
t.ClassDeclaration.check(path.node) ||
|
25
|
+
t.FunctionDeclaration.check(path.node)
|
26
|
+
) {
|
27
|
+
documentation.set('actualName', getNameOrValue(path.get('id')));
|
28
|
+
} else if (
|
29
|
+
t.ArrowFunctionExpression.check(path.node) ||
|
30
|
+
t.FunctionExpression.check(path.node) ||
|
31
|
+
isReactForwardRefCall(path, importer)
|
32
|
+
) {
|
33
|
+
let currentPath = path;
|
34
|
+
while (currentPath.parent) {
|
35
|
+
if (t.VariableDeclarator.check(currentPath.parent.node)) {
|
36
|
+
documentation.set(
|
37
|
+
'actualName',
|
38
|
+
getNameOrValue(currentPath.parent.get('id')),
|
39
|
+
);
|
40
|
+
return;
|
41
|
+
}
|
42
|
+
if (t.AssignmentExpression.check(currentPath.parent.node)) {
|
43
|
+
const leftPath = currentPath.parent.get('left');
|
44
|
+
if (
|
45
|
+
t.Identifier.check(leftPath.node) ||
|
46
|
+
t.Literal.check(leftPath.node)
|
47
|
+
) {
|
48
|
+
documentation.set('actualName', getNameOrValue(leftPath));
|
49
|
+
return;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
currentPath = currentPath.parent;
|
53
|
+
}
|
54
|
+
// Could not find an actual name
|
55
|
+
documentation.set('actualName', '');
|
56
|
+
}
|
57
|
+
}
|
@@ -0,0 +1,100 @@
|
|
1
|
+
import type { Options } from '@storybook/types';
|
2
|
+
import { CHAIN_ID, logger } from '@modern-js/utils';
|
3
|
+
import { RspackConfig } from '@modern-js/builder-rspack-provider';
|
4
|
+
import { WebpackChain } from '@modern-js/builder-webpack-provider';
|
5
|
+
|
6
|
+
export type DocgenOptions = {
|
7
|
+
reactDocgen?: 'react-docgen' | 'react-docgen-typescript' | false;
|
8
|
+
reactDocgenTypescriptOptions?: any;
|
9
|
+
};
|
10
|
+
|
11
|
+
export async function applyDocgenWebpack(
|
12
|
+
chain: WebpackChain,
|
13
|
+
options: Options,
|
14
|
+
) {
|
15
|
+
const typescriptOptions: DocgenOptions = await options.presets.apply(
|
16
|
+
'typescript',
|
17
|
+
{},
|
18
|
+
);
|
19
|
+
|
20
|
+
const { reactDocgen, reactDocgenTypescriptOptions } = typescriptOptions || {};
|
21
|
+
|
22
|
+
if (typeof reactDocgen !== 'string') {
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
|
26
|
+
if (reactDocgen === 'react-docgen-typescript') {
|
27
|
+
const { ReactDocgenTypeScriptPlugin } = await import(
|
28
|
+
'@storybook/react-docgen-typescript-plugin'
|
29
|
+
);
|
30
|
+
chain.plugin('Storybook-docgen').use(ReactDocgenTypeScriptPlugin, [
|
31
|
+
{
|
32
|
+
...reactDocgenTypescriptOptions,
|
33
|
+
savePropValueAsString: true,
|
34
|
+
},
|
35
|
+
]);
|
36
|
+
} else if (reactDocgen === 'react-docgen') {
|
37
|
+
// use babel react-docgen, its faster
|
38
|
+
const loader = require.resolve('./loader');
|
39
|
+
const resolveOptions = chain.toConfig().resolve;
|
40
|
+
|
41
|
+
chain.module
|
42
|
+
.rule(CHAIN_ID.RULE.JS)
|
43
|
+
.use(CHAIN_ID.USE.REACT_DOCGEN)
|
44
|
+
.loader(loader)
|
45
|
+
.options({
|
46
|
+
resolveOptions,
|
47
|
+
})
|
48
|
+
.after(CHAIN_ID.USE.BABEL)
|
49
|
+
.after(CHAIN_ID.USE.ESBUILD)
|
50
|
+
.after(CHAIN_ID.USE.SWC)
|
51
|
+
.end();
|
52
|
+
|
53
|
+
const tsRuls = chain.module.rule(CHAIN_ID.RULE.TS);
|
54
|
+
if (tsRuls.uses.values().length !== 0) {
|
55
|
+
tsRuls
|
56
|
+
.use(CHAIN_ID.USE.REACT_DOCGEN)
|
57
|
+
.loader(loader)
|
58
|
+
.options({
|
59
|
+
resolveOptions,
|
60
|
+
})
|
61
|
+
.after(CHAIN_ID.USE.TS)
|
62
|
+
.after(CHAIN_ID.USE.ESBUILD)
|
63
|
+
.after(CHAIN_ID.USE.SWC)
|
64
|
+
.end();
|
65
|
+
}
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
export async function applyDocgenRspack(
|
70
|
+
config: RspackConfig,
|
71
|
+
options: Options,
|
72
|
+
) {
|
73
|
+
const typescriptOptions: { reactDocgen?: 'react-docgen' } =
|
74
|
+
await options.presets.apply('typescript', {});
|
75
|
+
|
76
|
+
const { reactDocgen } = typescriptOptions || {};
|
77
|
+
|
78
|
+
if (reactDocgen !== 'react-docgen') {
|
79
|
+
if (reactDocgen !== false && reactDocgen !== undefined) {
|
80
|
+
logger.warn(
|
81
|
+
`Rspack currently only support 'typescript.reactDocgen: react-docgen' for auto docs generation, but you specified ${reactDocgen}`,
|
82
|
+
);
|
83
|
+
}
|
84
|
+
return;
|
85
|
+
}
|
86
|
+
|
87
|
+
// For rspack, just add a new rule
|
88
|
+
config.module ??= {};
|
89
|
+
config.module.rules ??= [];
|
90
|
+
config.module.rules.push({
|
91
|
+
test: /\.(tsx?|jsx?)$/,
|
92
|
+
exclude: /node_modules/,
|
93
|
+
use: {
|
94
|
+
loader: require.resolve('./loader'),
|
95
|
+
options: {
|
96
|
+
resolveOptions: config.resolve,
|
97
|
+
},
|
98
|
+
},
|
99
|
+
});
|
100
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
// @ts-expect-error
|
2
|
+
import type { Tinypool } from 'tinypool';
|
3
|
+
|
4
|
+
let tinyPoolPromise: Promise<Tinypool> | null = null;
|
5
|
+
|
6
|
+
async function docLoader(this: any, source: string, map: string, data: any) {
|
7
|
+
const callback = this.async();
|
8
|
+
|
9
|
+
if (!tinyPoolPromise) {
|
10
|
+
tinyPoolPromise = import('tinypool').then(({ Tinypool }) => {
|
11
|
+
return new Tinypool({
|
12
|
+
filename: require.resolve('./process'),
|
13
|
+
});
|
14
|
+
});
|
15
|
+
}
|
16
|
+
|
17
|
+
const tinyPool = await tinyPoolPromise;
|
18
|
+
|
19
|
+
const result: [string, string] | null = await tinyPool.run({
|
20
|
+
source,
|
21
|
+
map,
|
22
|
+
filename: this.resourcePath,
|
23
|
+
data,
|
24
|
+
});
|
25
|
+
|
26
|
+
if (result) {
|
27
|
+
const [docgen, outputMap] = result;
|
28
|
+
callback(null, `${source}\n${docgen}`, outputMap, data);
|
29
|
+
} else {
|
30
|
+
callback(null, source, map, data);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
export default docLoader;
|