-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
storybook.impl.ts
123 lines (109 loc) · 3.22 KB
/
storybook.impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import 'dotenv/config';
import { basename, join, sep } from 'path';
import { tmpdir } from 'os';
import { constants, copyFileSync, mkdtempSync, statSync } from 'fs';
import { buildDevStandalone } from '@storybook/core/server';
import { getStorybookFrameworkPath, setStorybookAppProject } from '../utils';
import { ExecutorContext } from '@nrwl/devkit';
export interface StorybookConfig {
configFolder?: string;
configPath?: string;
pluginPath?: string;
srcRoot?: string;
}
export interface StorybookExecutorOptions {
uiFramework: string;
projectBuildConfig?: string;
config: StorybookConfig;
host?: string;
port?: number;
quiet?: boolean;
https?: boolean;
sslCert?: string;
sslKey?: string;
staticDir?: string[];
watch?: boolean;
docsMode?: boolean;
}
export default async function* storybookExecutor(
options: StorybookExecutorOptions,
context: ExecutorContext
) {
let frameworkPath = getStorybookFrameworkPath(options.uiFramework);
const frameworkOptions = (await import(frameworkPath)).default;
const option = storybookOptionMapper(options, frameworkOptions, context);
await runInstance(option);
yield { success: true };
// This Promise intentionally never resolves, leaving the process running
await new Promise<{ success: boolean }>(() => {});
}
function runInstance(options: StorybookExecutorOptions) {
process.env.NODE_ENV ??= 'development';
return buildDevStandalone({ ...options, ci: true });
}
function storybookOptionMapper(
builderOptions: StorybookExecutorOptions,
frameworkOptions: any,
context: ExecutorContext
) {
setStorybookAppProject(context, builderOptions.projectBuildConfig);
const storybookConfig = findOrCreateConfig(builderOptions.config, context);
const optionsWithFramework = {
...builderOptions,
mode: 'dev',
configDir: storybookConfig,
...frameworkOptions,
frameworkPresets: [...(frameworkOptions.frameworkPresets || [])],
};
optionsWithFramework.config;
return optionsWithFramework;
}
function findOrCreateConfig(
config: StorybookConfig,
context: ExecutorContext
): string {
const sourceRoot = context.workspace.projects[context.projectName].root;
if (config.configFolder && statSync(config.configFolder).isDirectory()) {
return config.configFolder;
} else if (
statSync(config.configPath).isFile() &&
statSync(config.pluginPath).isFile() &&
statSync(config.srcRoot).isFile()
) {
return createStorybookConfig(
config.configPath,
config.pluginPath,
config.srcRoot
);
} else if (
statSync(join(context.root, sourceRoot, '.storybook')).isDirectory()
) {
return join(context.root, sourceRoot, '.storybook');
}
throw new Error('No configuration settings');
}
function createStorybookConfig(
configPath: string,
pluginPath: string,
srcRoot: string
): string {
const tmpDir = tmpdir();
const tmpFolder = `${tmpDir}${sep}`;
mkdtempSync(tmpFolder);
copyFileSync(
configPath,
`${tmpFolder}/${basename(configPath)}`,
constants.COPYFILE_EXCL
);
copyFileSync(
pluginPath,
`${tmpFolder}/${basename(pluginPath)}`,
constants.COPYFILE_EXCL
);
copyFileSync(
srcRoot,
`${tmpFolder}/${basename(srcRoot)}`,
constants.COPYFILE_EXCL
);
return tmpFolder;
}