@nx/storybook 23.2.0-beta.0 → 23.2.0-beta.10
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/dist/src/generators/configuration/configuration.js +5 -3
- package/dist/src/generators/configuration/lib/util-functions.d.ts +2 -2
- package/dist/src/generators/configuration/lib/util-functions.js +8 -7
- package/dist/src/generators/configuration/schema.d.ts +2 -2
- package/dist/src/generators/configuration/schema.json +1 -2
- package/dist/src/generators/migrate-10/migrate-10.js +1 -2
- package/dist/src/generators/migrate-8/helper-functions.js +2 -2
- package/dist/src/generators/migrate-8/migrate-8.js +1 -2
- package/dist/src/generators/migrate-9/helper-functions.js +2 -2
- package/dist/src/generators/migrate-9/migrate-9.js +1 -2
- package/dist/src/migrations/update-21-1-0/update-sb-9.js +2 -2
- package/dist/src/migrations/update-22-1-0/migrate-to-storybook-10.js +2 -2
- package/dist/src/plugins/plugin.js +136 -35
- package/dist/src/utils/utilities.js +8 -11
- package/dist/src/utils/versions.d.ts +2 -0
- package/dist/src/utils/versions.js +26 -5
- package/migrations.json +13 -0
- package/package.json +7 -7
|
@@ -76,9 +76,9 @@ async function configurationGeneratorInternal(tree, rawSchema) {
|
|
|
76
76
|
(0, util_functions_1.configureTsSolutionConfig)(tree, schema);
|
|
77
77
|
(0, util_functions_1.updateLintConfig)(tree, schema);
|
|
78
78
|
(0, util_functions_1.addBuildStorybookToCacheableOperations)(tree);
|
|
79
|
-
(0, util_functions_1.addStorybookToNamedInputs)(tree);
|
|
79
|
+
(0, util_functions_1.addStorybookToNamedInputs)(tree, schema);
|
|
80
80
|
if (!hasPlugin) {
|
|
81
|
-
(0, util_functions_1.addStorybookToTargetDefaults)(tree);
|
|
81
|
+
(0, util_functions_1.addStorybookToTargetDefaults)(tree, schema);
|
|
82
82
|
}
|
|
83
83
|
let devDeps = {};
|
|
84
84
|
if (!hasPlugin || schema.addExplicitTargets) {
|
|
@@ -96,6 +96,9 @@ async function configurationGeneratorInternal(tree, rawSchema) {
|
|
|
96
96
|
else {
|
|
97
97
|
devDeps['storybook'] = (0, utilities_1.getStorybookVersionToInstall)(tree);
|
|
98
98
|
}
|
|
99
|
+
if (schema.interactionTests) {
|
|
100
|
+
devDeps['@storybook/test-runner'] = (0, versions_1.versions)(tree).testRunnerVersion;
|
|
101
|
+
}
|
|
99
102
|
if (schema.tsConfiguration) {
|
|
100
103
|
devDeps['ts-node'] = versions_1.tsNodeVersion;
|
|
101
104
|
}
|
|
@@ -128,7 +131,6 @@ function normalizeSchema(tree, schema) {
|
|
|
128
131
|
nxJson.useInferencePlugins !== false;
|
|
129
132
|
const defaults = {
|
|
130
133
|
interactionTests: true,
|
|
131
|
-
linter: 'eslint',
|
|
132
134
|
js: false,
|
|
133
135
|
tsConfiguration: true,
|
|
134
136
|
addPlugin,
|
|
@@ -17,8 +17,8 @@ export declare function configureTsSolutionConfig(tree: Tree, schema: StorybookC
|
|
|
17
17
|
*/
|
|
18
18
|
export declare function updateLintConfig(tree: Tree, schema: StorybookConfigureSchema): void;
|
|
19
19
|
export declare function normalizeSchema(schema: StorybookConfigureSchema): StorybookConfigureSchema;
|
|
20
|
-
export declare function addStorybookToNamedInputs(tree: Tree): void;
|
|
21
|
-
export declare function addStorybookToTargetDefaults(tree: Tree, setCache?: boolean): void;
|
|
20
|
+
export declare function addStorybookToNamedInputs(tree: Tree, schema: StorybookConfigureSchema): void;
|
|
21
|
+
export declare function addStorybookToTargetDefaults(tree: Tree, schema: StorybookConfigureSchema, setCache?: boolean): void;
|
|
22
22
|
export declare function createProjectStorybookDir(tree: Tree, projectName: string, uiFramework: UiFramework, js: boolean, tsConfiguration: boolean, root: string, projectType: string, projectIsRootProjectInStandaloneWorkspace: boolean, interactionTests: boolean, mainDir?: string, isNextJs?: boolean, usesSwc?: boolean, usesVite?: boolean, viteConfigFilePath?: string, hasPlugin?: boolean, viteConfigFileName?: string, usesReactNative?: boolean): void;
|
|
23
23
|
export declare function getTsConfigPath(tree: Tree, projectName: string, path?: string): string;
|
|
24
24
|
export declare function addBuildStorybookToCacheableOperations(tree: Tree): void;
|
|
@@ -74,7 +74,7 @@ function addAngularStorybookTarget(tree, projectName, interactionTests) {
|
|
|
74
74
|
options: {
|
|
75
75
|
port: 4400,
|
|
76
76
|
configDir: `${projectConfig.root}/.storybook`,
|
|
77
|
-
browserTarget: `${projectName}:${ngBuildTarget
|
|
77
|
+
browserTarget: `${projectName}:${ngBuildTarget ?? 'build-storybook'}`,
|
|
78
78
|
compodoc: false,
|
|
79
79
|
},
|
|
80
80
|
configurations: {
|
|
@@ -89,7 +89,7 @@ function addAngularStorybookTarget(tree, projectName, interactionTests) {
|
|
|
89
89
|
options: {
|
|
90
90
|
outputDir: (0, devkit_1.joinPathFragments)('dist/storybook', projectName),
|
|
91
91
|
configDir: `${projectConfig.root}/.storybook`,
|
|
92
|
-
browserTarget: `${projectName}:${ngBuildTarget
|
|
92
|
+
browserTarget: `${projectName}:${ngBuildTarget ?? 'build-storybook'}`,
|
|
93
93
|
compodoc: false,
|
|
94
94
|
},
|
|
95
95
|
configurations: {
|
|
@@ -345,7 +345,6 @@ function updateLintConfig(tree, schema) {
|
|
|
345
345
|
function normalizeSchema(schema) {
|
|
346
346
|
const defaults = {
|
|
347
347
|
configureCypress: true,
|
|
348
|
-
linter: 'eslint',
|
|
349
348
|
js: false,
|
|
350
349
|
};
|
|
351
350
|
return {
|
|
@@ -353,7 +352,7 @@ function normalizeSchema(schema) {
|
|
|
353
352
|
...schema,
|
|
354
353
|
};
|
|
355
354
|
}
|
|
356
|
-
function addStorybookToNamedInputs(tree) {
|
|
355
|
+
function addStorybookToNamedInputs(tree, schema) {
|
|
357
356
|
const nxJson = (0, devkit_1.readNxJson)(tree);
|
|
358
357
|
if (nxJson.namedInputs) {
|
|
359
358
|
const hasProductionFileset = !!nxJson.namedInputs?.production;
|
|
@@ -364,14 +363,15 @@ function addStorybookToNamedInputs(tree) {
|
|
|
364
363
|
if (!nxJson.namedInputs.production.includes('!{projectRoot}/.storybook/**/*')) {
|
|
365
364
|
nxJson.namedInputs.production.push('!{projectRoot}/.storybook/**/*');
|
|
366
365
|
}
|
|
367
|
-
if (
|
|
366
|
+
if (schema.uiFramework !== '@storybook/angular' &&
|
|
367
|
+
!nxJson.namedInputs.production.includes('!{projectRoot}/tsconfig.storybook.json')) {
|
|
368
368
|
nxJson.namedInputs.production.push('!{projectRoot}/tsconfig.storybook.json');
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
(0, devkit_1.updateNxJson)(tree, nxJson);
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
|
-
function addStorybookToTargetDefaults(tree, setCache = true) {
|
|
374
|
+
function addStorybookToTargetDefaults(tree, schema, setCache = true) {
|
|
375
375
|
const nxJson = (0, devkit_1.readNxJson)(tree) ?? {};
|
|
376
376
|
const existing = (0, internal_2.findTargetDefault)(nxJson.targetDefaults, {
|
|
377
377
|
target: 'build-storybook',
|
|
@@ -391,7 +391,8 @@ function addStorybookToTargetDefaults(tree, setCache = true) {
|
|
|
391
391
|
const negatedIndex = inputs.indexOf('!{projectRoot}/.storybook/**/*');
|
|
392
392
|
if (negatedIndex !== -1)
|
|
393
393
|
inputs.splice(negatedIndex, 1);
|
|
394
|
-
if (
|
|
394
|
+
if (schema.uiFramework !== '@storybook/angular' &&
|
|
395
|
+
!inputs.includes('{projectRoot}/tsconfig.storybook.json')) {
|
|
395
396
|
inputs.push('{projectRoot}/tsconfig.storybook.json');
|
|
396
397
|
}
|
|
397
398
|
(0, internal_2.upsertTargetDefault)(tree, nxJson, {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LinterType } from '@nx/js';
|
|
2
2
|
import { UiFramework } from '../../utils/models';
|
|
3
3
|
|
|
4
4
|
export interface StorybookConfigureSchema {
|
|
5
5
|
project: string;
|
|
6
6
|
uiFramework?: UiFramework;
|
|
7
|
-
linter?:
|
|
7
|
+
linter?: LinterType;
|
|
8
8
|
js?: boolean;
|
|
9
9
|
interactionTests?: boolean;
|
|
10
10
|
tsConfiguration?: boolean;
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.migrate10Generator = migrate10Generator;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const output_1 = require("nx/src/utils/output");
|
|
6
5
|
const calling_storybook_cli_1 = require("./calling-storybook-cli");
|
|
7
6
|
const path_1 = require("path");
|
|
8
7
|
const fs_1 = require("fs");
|
|
@@ -11,7 +10,7 @@ async function migrate10Generator(tree, schema) {
|
|
|
11
10
|
(0, assert_supported_storybook_version_1.assertSupportedStorybookVersion)(tree);
|
|
12
11
|
const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
|
|
13
12
|
if (!(0, calling_storybook_cli_1.checkStorybookInstalled)(packageJson)) {
|
|
14
|
-
|
|
13
|
+
devkit_1.output.error({
|
|
15
14
|
title: 'No Storybook packages installed',
|
|
16
15
|
bodyLines: [
|
|
17
16
|
`🚨 Nx did not find any Storybook packages installed in your workspace.`,
|
|
@@ -6,9 +6,9 @@ exports.handleMigrationResult = handleMigrationResult;
|
|
|
6
6
|
exports.checkStorybookInstalled = checkStorybookInstalled;
|
|
7
7
|
exports.logResult = logResult;
|
|
8
8
|
const devkit_1 = require("@nx/devkit");
|
|
9
|
-
const fileutils_1 = require("nx/src/utils/fileutils");
|
|
10
9
|
const fs_1 = require("fs");
|
|
11
10
|
const path_1 = require("path");
|
|
11
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
12
12
|
function onlyShowGuide(storybookProjects) {
|
|
13
13
|
const packageManager = (0, devkit_1.detectPackageManager)();
|
|
14
14
|
const pm = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
|
@@ -65,7 +65,7 @@ function getAllStorybookInfo(tree) {
|
|
|
65
65
|
return allStorybookDirs;
|
|
66
66
|
}
|
|
67
67
|
function handleMigrationResult(migrateResult, allStorybookProjects) {
|
|
68
|
-
if ((0,
|
|
68
|
+
if ((0, internal_1.fileExists)((0, path_1.join)(devkit_1.workspaceRoot, 'migration-storybook.log')) &&
|
|
69
69
|
Object.keys(migrateResult.successfulProjects)?.length) {
|
|
70
70
|
const sbLogFile = (0, fs_1.readFileSync)((0, path_1.join)(devkit_1.workspaceRoot, 'migration-storybook.log'), 'utf-8');
|
|
71
71
|
Object.keys(migrateResult.successfulProjects).forEach((projectName) => {
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.migrate8Generator = migrate8Generator;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const output_1 = require("nx/src/utils/output");
|
|
6
5
|
const calling_storybook_cli_1 = require("./calling-storybook-cli");
|
|
7
6
|
const helper_functions_1 = require("./helper-functions");
|
|
8
7
|
async function migrate8Generator(tree, schema) {
|
|
9
8
|
const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
|
|
10
9
|
if (!(0, helper_functions_1.checkStorybookInstalled)(packageJson)) {
|
|
11
|
-
|
|
10
|
+
devkit_1.output.error({
|
|
12
11
|
title: 'No Storybook packages installed',
|
|
13
12
|
bodyLines: [
|
|
14
13
|
`🚨 Nx did not find any Storybook packages installed in your workspace.`,
|
|
@@ -6,9 +6,9 @@ exports.handleMigrationResult = handleMigrationResult;
|
|
|
6
6
|
exports.checkStorybookInstalled = checkStorybookInstalled;
|
|
7
7
|
exports.logResult = logResult;
|
|
8
8
|
const devkit_1 = require("@nx/devkit");
|
|
9
|
-
const fileutils_1 = require("nx/src/utils/fileutils");
|
|
10
9
|
const fs_1 = require("fs");
|
|
11
10
|
const path_1 = require("path");
|
|
11
|
+
const internal_1 = require("@nx/devkit/internal");
|
|
12
12
|
function onlyShowGuide(storybookProjects) {
|
|
13
13
|
const packageManager = (0, devkit_1.detectPackageManager)();
|
|
14
14
|
const pm = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
|
@@ -66,7 +66,7 @@ function getAllStorybookInfo(tree) {
|
|
|
66
66
|
return allStorybookDirs;
|
|
67
67
|
}
|
|
68
68
|
function handleMigrationResult(migrateResult, allStorybookProjects) {
|
|
69
|
-
if ((0,
|
|
69
|
+
if ((0, internal_1.fileExists)((0, path_1.join)(devkit_1.workspaceRoot, 'migration-storybook.log')) &&
|
|
70
70
|
Object.keys(migrateResult.successfulProjects)?.length) {
|
|
71
71
|
const sbLogFile = (0, fs_1.readFileSync)((0, path_1.join)(devkit_1.workspaceRoot, 'migration-storybook.log'), 'utf-8');
|
|
72
72
|
Object.keys(migrateResult.successfulProjects).forEach((projectName) => {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.migrate9Generator = migrate9Generator;
|
|
4
4
|
const devkit_1 = require("@nx/devkit");
|
|
5
|
-
const output_1 = require("nx/src/utils/output");
|
|
6
5
|
const calling_storybook_cli_1 = require("./calling-storybook-cli");
|
|
7
6
|
const helper_functions_1 = require("./helper-functions");
|
|
8
7
|
const assert_supported_storybook_version_1 = require("../../utils/assert-supported-storybook-version");
|
|
@@ -11,7 +10,7 @@ async function migrate9Generator(tree, schema) {
|
|
|
11
10
|
schema.versionTag = schema.versionTag ?? 'latest';
|
|
12
11
|
const packageJson = (0, devkit_1.readJson)(tree, 'package.json');
|
|
13
12
|
if (!(0, helper_functions_1.checkStorybookInstalled)(packageJson)) {
|
|
14
|
-
|
|
13
|
+
devkit_1.output.error({
|
|
15
14
|
title: 'No Storybook packages installed',
|
|
16
15
|
bodyLines: [
|
|
17
16
|
`🚨 Nx did not find any Storybook packages installed in your workspace.`,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = changeStorybookTargets;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const migrate_9_1 = tslib_1.__importDefault(require("../../generators/migrate-9/migrate-9"));
|
|
7
7
|
const utilities_1 = require("../../utils/utilities");
|
|
8
8
|
async function changeStorybookTargets(tree) {
|
|
@@ -18,7 +18,7 @@ async function changeStorybookTargets(tree) {
|
|
|
18
18
|
*/
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
devkit_1.output.log({
|
|
22
22
|
title: 'Migrating Storybook to v9',
|
|
23
23
|
bodyLines: [
|
|
24
24
|
`🚀 This migration will update your Storybook configuration to v9.`,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.default = migrateToStorybook10;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const migrate_10_1 = tslib_1.__importDefault(require("../../generators/migrate-10/migrate-10"));
|
|
7
7
|
async function migrateToStorybook10(tree) {
|
|
8
|
-
|
|
8
|
+
devkit_1.output.log({
|
|
9
9
|
title: 'Migrating Storybook to v10',
|
|
10
10
|
bodyLines: [
|
|
11
11
|
`🚀 This migration will update your Storybook configuration to v10.`,
|
|
@@ -5,11 +5,10 @@ const internal_1 = require("@nx/devkit/internal");
|
|
|
5
5
|
const devkit_1 = require("@nx/devkit");
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
const fs_1 = require("fs");
|
|
8
|
-
const cache_directory_1 = require("nx/src/utils/cache-directory");
|
|
9
8
|
const js_1 = require("@nx/js");
|
|
10
|
-
const file_hasher_1 = require("nx/src/hasher/file-hasher");
|
|
11
9
|
const tsquery_1 = require("@phenomnomnominal/tsquery");
|
|
12
10
|
const internal_2 = require("@nx/js/internal");
|
|
11
|
+
const utilities_1 = require("../utils/utilities");
|
|
13
12
|
/**
|
|
14
13
|
* @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
|
|
15
14
|
*/
|
|
@@ -18,12 +17,29 @@ const createDependencies = () => {
|
|
|
18
17
|
};
|
|
19
18
|
exports.createDependencies = createDependencies;
|
|
20
19
|
const storybookConfigGlob = '**/.storybook/main.{js,ts,mjs,mts,cjs,cts}';
|
|
20
|
+
// Vite-builder frameworks we infer the addon target for. The addon itself only
|
|
21
|
+
// checks that the resolved builder is Vite, so this list is conservative rather
|
|
22
|
+
// than exhaustive. `@storybook/sveltekit` uses the Vite builder despite the name.
|
|
23
|
+
const VITE_BUILDER_FRAMEWORKS = new Set([
|
|
24
|
+
'@storybook/angular-vite',
|
|
25
|
+
'@storybook/react-vite',
|
|
26
|
+
'@storybook/react-native-web-vite',
|
|
27
|
+
'@storybook/tanstack-react',
|
|
28
|
+
'@storybook/vue-vite',
|
|
29
|
+
'@storybook/vue3-vite',
|
|
30
|
+
'@storybook/svelte-vite',
|
|
31
|
+
'@storybook/sveltekit',
|
|
32
|
+
'@storybook/web-components-vite',
|
|
33
|
+
'@storybook/html-vite',
|
|
34
|
+
'@storybook/preact-vite',
|
|
35
|
+
'@storybook/nextjs-vite',
|
|
36
|
+
]);
|
|
21
37
|
exports.createNodes = [
|
|
22
38
|
storybookConfigGlob,
|
|
23
39
|
async (configFilePaths, options, context) => {
|
|
24
40
|
const normalizedOptions = normalizeOptions(options);
|
|
25
|
-
const optionsHash = (0,
|
|
26
|
-
const cachePath = (0, path_1.join)(
|
|
41
|
+
const optionsHash = (0, internal_1.hashObject)(normalizedOptions);
|
|
42
|
+
const cachePath = (0, path_1.join)(internal_1.workspaceDataDirectory, `storybook-${optionsHash}.hash`);
|
|
27
43
|
const targetsCache = new internal_1.PluginCache(cachePath);
|
|
28
44
|
const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
|
|
29
45
|
const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
|
|
@@ -71,9 +87,9 @@ function getProjectRootFromConfigPath(configFilePath) {
|
|
|
71
87
|
return projectRoot;
|
|
72
88
|
}
|
|
73
89
|
async function createNodesInternal(configFilePath, options, context, targetsCache, pmc, projectRoot, hash) {
|
|
74
|
-
const projectName =
|
|
90
|
+
const { projectName, angularBuildTarget } = getProjectMetadata(projectRoot, context.workspaceRoot);
|
|
75
91
|
if (!targetsCache.has(hash)) {
|
|
76
|
-
targetsCache.set(hash, await buildStorybookTargets(configFilePath, projectRoot, options, context, projectName, pmc));
|
|
92
|
+
targetsCache.set(hash, await buildStorybookTargets(configFilePath, projectRoot, options, context, projectName, angularBuildTarget, pmc));
|
|
77
93
|
}
|
|
78
94
|
const result = {
|
|
79
95
|
projects: {
|
|
@@ -85,35 +101,51 @@ async function createNodesInternal(configFilePath, options, context, targetsCach
|
|
|
85
101
|
};
|
|
86
102
|
return result;
|
|
87
103
|
}
|
|
88
|
-
async function buildStorybookTargets(configFilePath, projectRoot, options, context, projectName, pmc) {
|
|
104
|
+
async function buildStorybookTargets(configFilePath, projectRoot, options, context, projectName, angularBuildTarget, pmc) {
|
|
89
105
|
const buildOutputs = getOutputs();
|
|
90
106
|
const namedInputs = (0, internal_1.getNamedInputs)(projectRoot, context);
|
|
91
107
|
// First attempt to do a very fast lookup for the framework
|
|
92
108
|
// If that fails, the framework might be inherited, so do a very heavyweight lookup
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
// The slow path returns whatever the config holds, which for the common
|
|
110
|
+
// `getAbsolutePath('@storybook/react-vite')` shape is a resolved path.
|
|
111
|
+
const storybookFramework = normalizePackageName((await getStorybookFramework(configFilePath, context)) ||
|
|
112
|
+
(await getStorybookFullyResolvedFramework(configFilePath, context)));
|
|
95
113
|
const frameworkIsAngular = storybookFramework === '@storybook/angular';
|
|
96
114
|
if (frameworkIsAngular && !projectName) {
|
|
97
115
|
throw new Error(`Could not find a name for the project at '${projectRoot}'. Please make sure that the project has a package.json or project.json file with name specified.`);
|
|
98
116
|
}
|
|
99
117
|
const targets = {};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
118
|
+
// Resolution alone is not enough: the addon lives in the root package.json, so
|
|
119
|
+
// it resolves for every project. Registration in this project's own config is
|
|
120
|
+
// what makes it ours. Resolve first - it is a stat walk, while reading the
|
|
121
|
+
// registration executes the user's config.
|
|
122
|
+
const usesVitestAddon = VITE_BUILDER_FRAMEWORKS.has(storybookFramework) &&
|
|
123
|
+
isInstalled('@storybook/addon-vitest', context.workspaceRoot, projectRoot) &&
|
|
124
|
+
(await registersVitestAddon(configFilePath, context));
|
|
125
|
+
const hasTestRunner = isInstalled('@storybook/test-runner', context.workspaceRoot, projectRoot);
|
|
126
|
+
// Falls back to the storybook build target, whose name is configurable, so
|
|
127
|
+
// resolve it from the options rather than assuming the default.
|
|
128
|
+
const browserTarget = `${projectName}:${angularBuildTarget ?? options.buildStorybookTargetName}`;
|
|
129
|
+
targets[options.buildStorybookTargetName] = buildTarget(namedInputs, buildOutputs, projectRoot, frameworkIsAngular, browserTarget, configFilePath, hasTestRunner);
|
|
130
|
+
targets[options.serveStorybookTargetName] = serveTarget(projectRoot, frameworkIsAngular, browserTarget, configFilePath);
|
|
131
|
+
if (usesVitestAddon) {
|
|
132
|
+
targets[options.testStorybookTargetName] = vitestTestTarget(projectRoot);
|
|
133
|
+
}
|
|
134
|
+
else if (hasTestRunner) {
|
|
103
135
|
targets[options.testStorybookTargetName] = testTarget(projectRoot);
|
|
104
136
|
}
|
|
105
137
|
targets[options.staticStorybookTargetName] = serveStaticTarget(options, projectRoot);
|
|
106
138
|
(0, internal_2.addBuildAndWatchDepsTargets)(context.workspaceRoot, projectRoot, targets, options, pmc);
|
|
107
139
|
return targets;
|
|
108
140
|
}
|
|
109
|
-
function buildTarget(namedInputs, outputs, projectRoot, frameworkIsAngular,
|
|
141
|
+
function buildTarget(namedInputs, outputs, projectRoot, frameworkIsAngular, browserTarget, configFilePath, hasTestRunner) {
|
|
110
142
|
let targetConfig;
|
|
111
143
|
if (frameworkIsAngular) {
|
|
112
144
|
targetConfig = {
|
|
113
145
|
executor: '@storybook/angular:build-storybook',
|
|
114
146
|
options: {
|
|
115
147
|
configDir: `${(0, path_1.dirname)(configFilePath)}`,
|
|
116
|
-
browserTarget
|
|
148
|
+
browserTarget,
|
|
117
149
|
compodoc: false,
|
|
118
150
|
outputDir: (0, devkit_1.joinPathFragments)(projectRoot, 'storybook-static'),
|
|
119
151
|
},
|
|
@@ -127,9 +159,7 @@ function buildTarget(namedInputs, outputs, projectRoot, frameworkIsAngular, proj
|
|
|
127
159
|
externalDependencies: [
|
|
128
160
|
'storybook',
|
|
129
161
|
'@storybook/angular',
|
|
130
|
-
|
|
131
|
-
? '@storybook/test-runner'
|
|
132
|
-
: undefined,
|
|
162
|
+
hasTestRunner ? '@storybook/test-runner' : undefined,
|
|
133
163
|
].filter(Boolean),
|
|
134
164
|
},
|
|
135
165
|
],
|
|
@@ -148,9 +178,7 @@ function buildTarget(namedInputs, outputs, projectRoot, frameworkIsAngular, proj
|
|
|
148
178
|
{
|
|
149
179
|
externalDependencies: [
|
|
150
180
|
'storybook',
|
|
151
|
-
|
|
152
|
-
? '@storybook/test-runner'
|
|
153
|
-
: undefined,
|
|
181
|
+
hasTestRunner ? '@storybook/test-runner' : undefined,
|
|
154
182
|
].filter(Boolean),
|
|
155
183
|
},
|
|
156
184
|
],
|
|
@@ -158,15 +186,18 @@ function buildTarget(namedInputs, outputs, projectRoot, frameworkIsAngular, proj
|
|
|
158
186
|
}
|
|
159
187
|
return targetConfig;
|
|
160
188
|
}
|
|
161
|
-
function serveTarget(projectRoot, frameworkIsAngular,
|
|
189
|
+
function serveTarget(projectRoot, frameworkIsAngular, browserTarget, configFilePath) {
|
|
162
190
|
if (frameworkIsAngular) {
|
|
163
191
|
return {
|
|
164
192
|
continuous: true,
|
|
165
193
|
executor: '@storybook/angular:start-storybook',
|
|
166
194
|
options: {
|
|
167
195
|
configDir: `${(0, path_1.dirname)(configFilePath)}`,
|
|
168
|
-
browserTarget
|
|
196
|
+
browserTarget,
|
|
169
197
|
compodoc: false,
|
|
198
|
+
// The builder defaults to 9009, but test-storybook looks for 6006. Match
|
|
199
|
+
// the port the non-Angular `storybook dev` target serves on.
|
|
200
|
+
port: 6006,
|
|
170
201
|
},
|
|
171
202
|
};
|
|
172
203
|
}
|
|
@@ -190,6 +221,24 @@ function testTarget(projectRoot) {
|
|
|
190
221
|
};
|
|
191
222
|
return targetConfig;
|
|
192
223
|
}
|
|
224
|
+
function vitestTestTarget(projectRoot) {
|
|
225
|
+
const targetConfig = {
|
|
226
|
+
// `--passWithNoTests` so the target is green before any stories exist. It does
|
|
227
|
+
// not mask a missing `storybook` project: that is a startup error either way.
|
|
228
|
+
command: `vitest run --project=storybook --passWithNoTests`,
|
|
229
|
+
options: { cwd: projectRoot },
|
|
230
|
+
inputs: [
|
|
231
|
+
{
|
|
232
|
+
externalDependencies: [
|
|
233
|
+
'storybook',
|
|
234
|
+
'@storybook/addon-vitest',
|
|
235
|
+
'vitest',
|
|
236
|
+
],
|
|
237
|
+
},
|
|
238
|
+
],
|
|
239
|
+
};
|
|
240
|
+
return targetConfig;
|
|
241
|
+
}
|
|
193
242
|
function serveStaticTarget(options, projectRoot) {
|
|
194
243
|
const targetConfig = {
|
|
195
244
|
dependsOn: [`${options.buildStorybookTargetName}`],
|
|
@@ -210,10 +259,11 @@ async function getStorybookFramework(configFilePath, context) {
|
|
|
210
259
|
return parseFrameworkName(mainTsJs);
|
|
211
260
|
}
|
|
212
261
|
const storybookConfigImportPackage = (0, tsquery_1.query)(importDeclarations, 'StringLiteral')?.[0];
|
|
213
|
-
|
|
262
|
+
const frameworkPackage = stringLiteralValue(storybookConfigImportPackage);
|
|
263
|
+
if (frameworkPackage === '@storybook/core-common') {
|
|
214
264
|
return parseFrameworkName(mainTsJs);
|
|
215
265
|
}
|
|
216
|
-
return
|
|
266
|
+
return frameworkPackage;
|
|
217
267
|
}
|
|
218
268
|
function parseFrameworkName(mainTsJs) {
|
|
219
269
|
const frameworkPropertyAssignment = (0, tsquery_1.query)(mainTsJs, `PropertyAssignment:has(Identifier:has([text="framework"]))`)?.[0];
|
|
@@ -226,9 +276,13 @@ function parseFrameworkName(mainTsJs) {
|
|
|
226
276
|
});
|
|
227
277
|
if (!namePropertyAssignment) {
|
|
228
278
|
const storybookConfigImportPackage = (0, tsquery_1.query)(frameworkPropertyAssignment, 'StringLiteral')?.[0];
|
|
229
|
-
return storybookConfigImportPackage
|
|
279
|
+
return stringLiteralValue(storybookConfigImportPackage);
|
|
230
280
|
}
|
|
231
|
-
return (0, tsquery_1.query)(namePropertyAssignment, `StringLiteral`)?.[0]
|
|
281
|
+
return stringLiteralValue((0, tsquery_1.query)(namePropertyAssignment, `StringLiteral`)?.[0]);
|
|
282
|
+
}
|
|
283
|
+
function stringLiteralValue(node) {
|
|
284
|
+
const value = node?.getText();
|
|
285
|
+
return value?.slice(1, -1);
|
|
232
286
|
}
|
|
233
287
|
async function getStorybookFullyResolvedFramework(configFilePath, context) {
|
|
234
288
|
const resolvedPath = (0, path_1.join)(context.workspaceRoot, configFilePath);
|
|
@@ -276,26 +330,73 @@ function normalizeOptions(options) {
|
|
|
276
330
|
watchDepsTargetName: options.watchDepsTargetName ?? 'watch-deps',
|
|
277
331
|
};
|
|
278
332
|
}
|
|
279
|
-
function
|
|
333
|
+
function getProjectMetadata(projectRoot, workspaceRoot) {
|
|
280
334
|
const packageJsonPath = (0, path_1.join)(workspaceRoot, projectRoot, 'package.json');
|
|
281
335
|
const projectJsonPath = (0, path_1.join)(workspaceRoot, projectRoot, 'project.json');
|
|
282
|
-
let
|
|
336
|
+
let projectJsonName;
|
|
337
|
+
let projectJsonTargets = {};
|
|
338
|
+
let packageJsonName;
|
|
339
|
+
let packageJsonTargets = {};
|
|
283
340
|
if ((0, fs_1.existsSync)(projectJsonPath)) {
|
|
284
341
|
const projectJson = (0, devkit_1.parseJson)((0, fs_1.readFileSync)(projectJsonPath, 'utf-8'));
|
|
285
|
-
|
|
342
|
+
projectJsonName = projectJson.name;
|
|
343
|
+
projectJsonTargets = projectJson.targets ?? {};
|
|
286
344
|
}
|
|
287
|
-
|
|
345
|
+
if ((0, fs_1.existsSync)(packageJsonPath)) {
|
|
288
346
|
const packageJson = (0, devkit_1.parseJson)((0, fs_1.readFileSync)(packageJsonPath, 'utf-8'));
|
|
289
|
-
|
|
347
|
+
packageJsonName = packageJson.name;
|
|
348
|
+
packageJsonTargets = packageJson.nx?.targets ?? {};
|
|
290
349
|
}
|
|
291
|
-
|
|
350
|
+
// Mirror how Nx itself names a project: project.json, then package.json, then
|
|
351
|
+
// the directory. Both files can carry targets, and project.json wins.
|
|
352
|
+
const targets = { ...packageJsonTargets, ...projectJsonTargets };
|
|
353
|
+
return {
|
|
354
|
+
projectName: projectJsonName ?? packageJsonName ?? nameFromRoot(projectRoot),
|
|
355
|
+
angularBuildTarget: (0, utilities_1.findStorybookAndBuildTargetsAndCompiler)(targets).ngBuildTarget,
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
// Same derivation as Nx's `toProjectName`. The workspace root has no directory
|
|
359
|
+
// segment to name it after, so leave it undefined and let the caller complain.
|
|
360
|
+
function nameFromRoot(projectRoot) {
|
|
361
|
+
const segment = projectRoot.split(/[\/\\]/g).pop();
|
|
362
|
+
return !segment || segment === '.' ? undefined : segment.toLowerCase();
|
|
363
|
+
}
|
|
364
|
+
async function registersVitestAddon(configFilePath, context) {
|
|
365
|
+
try {
|
|
366
|
+
const { addons } = await (0, internal_1.loadConfigFile)((0, path_1.join)(context.workspaceRoot, configFilePath));
|
|
367
|
+
return addons?.some(isVitestAddon) ?? false;
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function isVitestAddon(addon) {
|
|
374
|
+
const addonName = typeof addon === 'string'
|
|
375
|
+
? addon
|
|
376
|
+
: typeof addon === 'object' && addon !== null && 'name' in addon
|
|
377
|
+
? addon.name
|
|
378
|
+
: undefined;
|
|
379
|
+
return (typeof addonName === 'string' &&
|
|
380
|
+
normalizePackageName(addonName) === '@storybook/addon-vitest');
|
|
381
|
+
}
|
|
382
|
+
function normalizePackageName(packageName) {
|
|
383
|
+
return packageName
|
|
384
|
+
?.replace(/\\/g, '/')
|
|
385
|
+
.split('/')
|
|
386
|
+
.filter(Boolean)
|
|
387
|
+
.slice(-2)
|
|
388
|
+
.join('/');
|
|
292
389
|
}
|
|
293
|
-
|
|
390
|
+
// Resolved from the project first so a runner declared in the project's own
|
|
391
|
+
// package.json counts, not just one hoisted to the workspace root.
|
|
392
|
+
function isInstalled(packageName, workspaceRoot, projectRoot) {
|
|
294
393
|
try {
|
|
295
|
-
require.resolve(
|
|
394
|
+
require.resolve(packageName, {
|
|
395
|
+
paths: [(0, path_1.join)(workspaceRoot, projectRoot), workspaceRoot],
|
|
396
|
+
});
|
|
296
397
|
return true;
|
|
297
398
|
}
|
|
298
|
-
catch
|
|
399
|
+
catch {
|
|
299
400
|
return false;
|
|
300
401
|
}
|
|
301
402
|
}
|
|
@@ -67,24 +67,21 @@ function findStorybookAndBuildTargetsAndCompiler(targets) {
|
|
|
67
67
|
'@angular-devkit/build-angular:application',
|
|
68
68
|
'@angular-devkit/build-angular:browser',
|
|
69
69
|
'@angular-devkit/build-angular:browser-esbuild',
|
|
70
|
+
'@angular/build:application',
|
|
70
71
|
];
|
|
71
72
|
for (const target in targets) {
|
|
72
73
|
if (arrayOfBuilders.includes(targets[target].executor)) {
|
|
73
74
|
if (targets[target].executor === '@angular-devkit/build-angular:browser' ||
|
|
74
75
|
targets[target].executor ===
|
|
75
76
|
'@angular-devkit/build-angular:browser-esbuild' ||
|
|
76
|
-
targets[target].executor ===
|
|
77
|
+
targets[target].executor ===
|
|
78
|
+
'@angular-devkit/build-angular:application' ||
|
|
79
|
+
targets[target].executor === '@angular/build:application') {
|
|
77
80
|
/**
|
|
78
|
-
*
|
|
79
|
-
* @nx/angular:* executors
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
* (and maybe the other custom executors)
|
|
83
|
-
* does not support styles and extra options, so the user
|
|
84
|
-
* will be forced to switch to build-storybook to add extra options.
|
|
85
|
-
*
|
|
86
|
-
* So we might as well use the build-storybook by default to
|
|
87
|
-
* avoid any errors.
|
|
81
|
+
* Only the official Angular application/browser builders. The
|
|
82
|
+
* '@nx/angular:*' executors (ng-packagr-lite and friends) do not
|
|
83
|
+
* support styles and extra options, so a project on one of those is
|
|
84
|
+
* better served by build-storybook, which can carry those options.
|
|
88
85
|
*/
|
|
89
86
|
returnObject.ngBuildTarget = target;
|
|
90
87
|
}
|
|
@@ -8,8 +8,10 @@ export declare const storybookVersion = "^10.5.0";
|
|
|
8
8
|
export declare const reactVersion = "^18.2.0";
|
|
9
9
|
export declare const viteVersion = "^6.0.0";
|
|
10
10
|
export declare const coreJsVersion = "^3.36.1";
|
|
11
|
+
export declare const testRunnerVersion = "^0.24.0";
|
|
11
12
|
type StorybookVersions = {
|
|
12
13
|
storybookVersion: string;
|
|
14
|
+
testRunnerVersion: string;
|
|
13
15
|
};
|
|
14
16
|
export declare function versions(tree: Tree): StorybookVersions;
|
|
15
17
|
export declare function storybookMajorVersion(tree?: Tree): number | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.coreJsVersion = exports.viteVersion = exports.reactVersion = exports.storybookVersion = exports.minSupportedStorybookVersion = exports.tsLibVersion = exports.tsNodeVersion = exports.litVersion = exports.nxVersion = void 0;
|
|
3
|
+
exports.testRunnerVersion = exports.coreJsVersion = exports.viteVersion = exports.reactVersion = exports.storybookVersion = exports.minSupportedStorybookVersion = exports.tsLibVersion = exports.tsNodeVersion = exports.litVersion = exports.nxVersion = void 0;
|
|
4
4
|
exports.versions = versions;
|
|
5
5
|
exports.storybookMajorVersion = storybookMajorVersion;
|
|
6
6
|
exports.getInstalledStorybookVersion = getInstalledStorybookVersion;
|
|
@@ -17,20 +17,41 @@ exports.storybookVersion = '^10.5.0';
|
|
|
17
17
|
exports.reactVersion = '^18.2.0';
|
|
18
18
|
exports.viteVersion = '^6.0.0';
|
|
19
19
|
exports.coreJsVersion = '^3.36.1';
|
|
20
|
+
exports.testRunnerVersion = '^0.24.0';
|
|
20
21
|
const latestVersions = {
|
|
21
22
|
storybookVersion: exports.storybookVersion,
|
|
23
|
+
testRunnerVersion: exports.testRunnerVersion,
|
|
22
24
|
};
|
|
23
25
|
const versionMap = {
|
|
24
|
-
8: { storybookVersion: '^8.6.11' },
|
|
25
|
-
9: { storybookVersion: '^9.0.5' },
|
|
26
|
-
10: { storybookVersion: '^10.5.0' },
|
|
26
|
+
8: { storybookVersion: '^8.6.11', testRunnerVersion: '^0.21.0' },
|
|
27
|
+
9: { storybookVersion: '^9.0.5', testRunnerVersion: '^0.23.0' },
|
|
28
|
+
10: { storybookVersion: '^10.5.0', testRunnerVersion: exports.testRunnerVersion },
|
|
27
29
|
};
|
|
28
30
|
function versions(tree) {
|
|
29
31
|
const installedStorybookMajor = storybookMajorVersion(tree);
|
|
30
32
|
if (installedStorybookMajor === undefined) {
|
|
31
33
|
return latestVersions;
|
|
32
34
|
}
|
|
33
|
-
|
|
35
|
+
const compat = versionMap[installedStorybookMajor] ?? latestVersions;
|
|
36
|
+
// 0.20 is the first runner line to declare a storybook peer, and it peers ^8.2.
|
|
37
|
+
// Ranges that cannot reach 8.2 need 0.17, the earliest line built against 8.
|
|
38
|
+
if (installedStorybookMajor === 8 &&
|
|
39
|
+
!storybookVersionIntersects(tree, '>=8.2.0')) {
|
|
40
|
+
return { ...compat, testRunnerVersion: '^0.17.0' };
|
|
41
|
+
}
|
|
42
|
+
return compat;
|
|
43
|
+
}
|
|
44
|
+
function storybookVersionIntersects(tree, range) {
|
|
45
|
+
const installedVersion = getInstalledStorybookVersion(tree);
|
|
46
|
+
if (!installedVersion) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
return (0, semver_1.intersects)(installedVersion, range);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
34
55
|
}
|
|
35
56
|
function storybookMajorVersion(tree) {
|
|
36
57
|
const installedVersion = getInstalledStorybookVersion(tree);
|
package/migrations.json
CHANGED
|
@@ -435,6 +435,19 @@
|
|
|
435
435
|
"alwaysAddToPackageJson": false
|
|
436
436
|
}
|
|
437
437
|
}
|
|
438
|
+
},
|
|
439
|
+
"23.2.0-test-runner": {
|
|
440
|
+
"version": "23.2.0-beta.8",
|
|
441
|
+
"requires": {
|
|
442
|
+
"storybook": ">=10.0.0 <11.0.0",
|
|
443
|
+
"@storybook/test-runner": "<0.24.0"
|
|
444
|
+
},
|
|
445
|
+
"packages": {
|
|
446
|
+
"@storybook/test-runner": {
|
|
447
|
+
"version": "^0.24.0",
|
|
448
|
+
"alwaysAddToPackageJson": false
|
|
449
|
+
}
|
|
450
|
+
}
|
|
438
451
|
}
|
|
439
452
|
}
|
|
440
453
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nx/storybook",
|
|
3
|
-
"version": "23.2.0-beta.
|
|
3
|
+
"version": "23.2.0-beta.10",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"files": [
|
|
@@ -92,18 +92,18 @@
|
|
|
92
92
|
"@phenomnomnominal/tsquery": "~6.2.0",
|
|
93
93
|
"semver": "^7.6.3",
|
|
94
94
|
"tslib": "^2.3.0",
|
|
95
|
-
"@nx/devkit": "23.2.0-beta.
|
|
96
|
-
"@nx/cypress": "23.2.0-beta.
|
|
97
|
-
"@nx/js": "23.2.0-beta.
|
|
98
|
-
"@nx/eslint": "23.2.0-beta.
|
|
95
|
+
"@nx/devkit": "23.2.0-beta.10",
|
|
96
|
+
"@nx/cypress": "23.2.0-beta.10",
|
|
97
|
+
"@nx/js": "23.2.0-beta.10",
|
|
98
|
+
"@nx/eslint": "23.2.0-beta.10"
|
|
99
99
|
},
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"storybook": "9.0.6",
|
|
102
|
-
"nx": "23.2.0-beta.
|
|
102
|
+
"nx": "23.2.0-beta.10"
|
|
103
103
|
},
|
|
104
104
|
"peerDependencies": {
|
|
105
105
|
"storybook": ">=8.0.0 <11.0.0",
|
|
106
|
-
"@nx/web": "23.2.0-beta.
|
|
106
|
+
"@nx/web": "23.2.0-beta.10"
|
|
107
107
|
},
|
|
108
108
|
"peerDependenciesMeta": {
|
|
109
109
|
"@nx/web": {
|