Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat(storybook): add projectBuildConfig as an option in generator (#9655
)

Co-authored-by: Colum Ferry <cferry09@gmail.com>
  • Loading branch information
mandarini and Coly010 committed Apr 5, 2022
1 parent e42069b commit 9579aec
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 6 deletions.
4 changes: 4 additions & 0 deletions docs/generated/packages/angular.json
Expand Up @@ -1638,6 +1638,10 @@
"type": "string",
"enum": ["eslint", "none"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
}
},
"additionalProperties": false,
Expand Down
4 changes: 4 additions & 0 deletions docs/generated/packages/react.json
Expand Up @@ -620,6 +620,10 @@
"enum": ["eslint", "tslint"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
},
"standaloneConfig": {
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
"type": "boolean"
Expand Down
4 changes: 4 additions & 0 deletions docs/generated/packages/storybook.json
Expand Up @@ -76,6 +76,10 @@
"enum": ["eslint", "tslint", "none"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
},
"js": {
"type": "boolean",
"description": "Generate JavaScript files rather than TypeScript files.",
Expand Down
Expand Up @@ -7,4 +7,5 @@ export interface StorybookConfigurationOptions {
linter: Exclude<Linter, Linter.TsLint>;
name: string;
cypressDirectory?: string;
projectBuildConfig?: string;
}
Expand Up @@ -41,6 +41,10 @@
"type": "string",
"enum": ["eslint", "none"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
}
},
"additionalProperties": false,
Expand Down
Expand Up @@ -9,4 +9,5 @@ export interface StorybookConfigureSchema {
linter?: Linter;
cypressDirectory?: string;
standaloneConfig?: boolean;
projectBuildConfig?: string;
}
Expand Up @@ -47,6 +47,10 @@
"enum": ["eslint", "tslint"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
},
"standaloneConfig": {
"description": "Split the project configuration into `<projectRoot>/project.json` rather than including it inside `workspace.json`.",
"type": "boolean"
Expand Down
36 changes: 36 additions & 0 deletions packages/storybook/src/executors/utils.ts
Expand Up @@ -3,8 +3,10 @@ import {
joinPathFragments,
logger,
parseTargetString,
readProjectConfiguration,
readTargetOptions,
TargetConfiguration,
Tree,
} from '@nrwl/devkit';
import { checkAndCleanWithSemver } from '@nrwl/workspace/src/utilities/version-utils';
import 'dotenv/config';
Expand Down Expand Up @@ -302,6 +304,40 @@ export function isStorybookLT6() {
);
}

export function customProjectBuildConfigIsValid(
tree: Tree,
projectBuildConfig: string
): boolean {
if (projectBuildConfig.includes(':')) {
const { project, target } = parseTargetString(projectBuildConfig);
const projectConfig = readProjectConfiguration(tree, project);
if (projectConfig?.targets?.[target]) {
return true;
} else {
logger.warn(`
The projectBuildConfig you provided is not valid.
${!projectConfig ? 'The project ' + project + ' does not exist.' : ''}
${
projectConfig &&
!projectConfig.targets?.[target] &&
`The project ${project} does not have the target ${target}.`
}
The default projectBuildConfig is going to be used.
`);
}
} else {
try {
return Boolean(readProjectConfiguration(tree, projectBuildConfig));
} catch (e) {
logger.warn(`
The projectBuildConfig you provided is not valid.
The project ${projectBuildConfig} does not exist.
The default projectBuildConfig is going to be used.
`);
}
}
}

export function findStorybookAndBuildTargets(targets: {
[targetName: string]: TargetConfiguration;
}): {
Expand Down
116 changes: 115 additions & 1 deletion packages/storybook/src/generators/configuration/configuration.spec.ts
Expand Up @@ -9,9 +9,20 @@ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';

import { Linter } from '@nrwl/linter';
import { libraryGenerator } from '@nrwl/workspace/generators';

import { wrapAngularDevkitSchematic } from '@nrwl/devkit/ngcli-adapter';
import { TsConfig } from '../../utils/utilities';
import configurationGenerator from './configuration';
import { nxVersion, storybookVersion } from '../../utils/versions';

const runAngularLibrarySchematic = wrapAngularDevkitSchematic(
'@schematics/angular',
'library'
);

const runAngularApplicationSchematic = wrapAngularDevkitSchematic(
'@schematics/angular',
'application'
);

describe('@nrwl/storybook:configuration', () => {
let tree: Tree;
Expand Down Expand Up @@ -265,6 +276,109 @@ describe('@nrwl/storybook:configuration', () => {
});
});

it('should update workspace file for angular libs with custom projectBuildConfig', async () => {
const newTree = createTreeWithEmptyWorkspace();

await runAngularLibrarySchematic(newTree, {
name: 'ui-lib',
});

await runAngularApplicationSchematic(newTree, {
name: 'test-app',
});

writeJson(newTree, 'package.json', {
devDependencies: {
'@nrwl/storybook': nxVersion,
'@storybook/addon-essentials': storybookVersion,
'@storybook/angular': storybookVersion,
},
});

writeJson(newTree, 'ui-lib/tsconfig.json', {});
writeJson(newTree, 'test-app/tsconfig.json', {});

await configurationGenerator(newTree, {
name: 'ui-lib',
uiFramework: '@storybook/angular',
standaloneConfig: false,
projectBuildConfig: 'test-app',
});

const project = readProjectConfiguration(newTree, 'ui-lib');

expect(project.targets.storybook?.options?.projectBuildConfig).toBe(
'test-app'
);
});

it('should update workspace file for angular libs with default projectBuildConfig if the one provided is invalid', async () => {
const newTree = createTreeWithEmptyWorkspace();

await runAngularLibrarySchematic(newTree, {
name: 'ui-lib',
});

await runAngularApplicationSchematic(newTree, {
name: 'test-app',
});

writeJson(newTree, 'package.json', {
devDependencies: {
'@nrwl/storybook': nxVersion,
'@storybook/addon-essentials': storybookVersion,
'@storybook/angular': storybookVersion,
},
});

writeJson(newTree, 'ui-lib/tsconfig.json', {});
writeJson(newTree, 'test-app/tsconfig.json', {});

await configurationGenerator(newTree, {
name: 'ui-lib',
uiFramework: '@storybook/angular',
standaloneConfig: false,
projectBuildConfig: 'test-app:asdfasdf',
});

const project = readProjectConfiguration(newTree, 'ui-lib');

expect(project.targets.storybook?.options?.projectBuildConfig).toBe(
'ui-lib:build-storybook'
);
});

it('should update workspace file for angular libs with default projectBuildConfig if the project provided does not exist', async () => {
const newTree = createTreeWithEmptyWorkspace();

await runAngularLibrarySchematic(newTree, {
name: 'ui-lib',
});

writeJson(newTree, 'package.json', {
devDependencies: {
'@nrwl/storybook': nxVersion,
'@storybook/addon-essentials': storybookVersion,
'@storybook/angular': storybookVersion,
},
});

writeJson(newTree, 'ui-lib/tsconfig.json', {});

await configurationGenerator(newTree, {
name: 'ui-lib',
uiFramework: '@storybook/angular',
standaloneConfig: false,
projectBuildConfig: 'test-app',
});

const project = readProjectConfiguration(newTree, 'ui-lib');

expect(project.targets.storybook?.options?.projectBuildConfig).toBe(
'ui-lib:build-storybook'
);
});

it('should update `tsconfig.lib.json` file', async () => {
await configurationGenerator(tree, {
name: 'test-ui-lib',
Expand Down
26 changes: 21 additions & 5 deletions packages/storybook/src/generators/configuration/configuration.ts
Expand Up @@ -30,7 +30,10 @@ import { StorybookConfigureSchema } from './schema';
import { initGenerator } from '../init/init';
import { checkAndCleanWithSemver } from '@nrwl/workspace/src/utilities/version-utils';
import { gte } from 'semver';
import { findStorybookAndBuildTargets } from '../../executors/utils';
import {
customProjectBuildConfigIsValid,
findStorybookAndBuildTargets,
} from '../../executors/utils';
import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript';

export async function configurationGenerator(
Expand Down Expand Up @@ -63,7 +66,13 @@ export async function configurationGenerator(
configureTsProjectConfig(tree, schema);
configureTsSolutionConfig(tree, schema);
updateLintConfig(tree, schema);
addStorybookTask(tree, schema.name, schema.uiFramework, buildTarget);
addStorybookTask(
tree,
schema.name,
schema.uiFramework,
buildTarget,
schema.projectBuildConfig
);
if (schema.configureCypress) {
if (projectType !== 'application') {
const cypressTask = await cypressProjectGenerator(tree, {
Expand Down Expand Up @@ -326,7 +335,8 @@ function addStorybookTask(
tree: Tree,
projectName: string,
uiFramework: string,
buildTargetForAngularProjects: string
buildTargetForAngularProjects: string,
customProjectBuildConfig?: string
) {
if (uiFramework === '@storybook/react-native') {
return;
Expand All @@ -342,7 +352,10 @@ function addStorybookTask(
},
projectBuildConfig:
uiFramework === '@storybook/angular'
? buildTargetForAngularProjects
? customProjectBuildConfig &&
customProjectBuildConfigIsValid(tree, customProjectBuildConfig)
? customProjectBuildConfig
: buildTargetForAngularProjects
? projectName
: `${projectName}:build-storybook`
: undefined,
Expand All @@ -364,7 +377,10 @@ function addStorybookTask(
},
projectBuildConfig:
uiFramework === '@storybook/angular'
? buildTargetForAngularProjects
? customProjectBuildConfig &&
customProjectBuildConfigIsValid(tree, customProjectBuildConfig)
? customProjectBuildConfig
: buildTargetForAngularProjects
? projectName
: `${projectName}:build-storybook`
: undefined,
Expand Down
Expand Up @@ -11,4 +11,5 @@ export interface StorybookConfigureSchema {
js?: boolean;
cypressDirectory?: string;
standaloneConfig?: boolean;
projectBuildConfig?: string;
}
4 changes: 4 additions & 0 deletions packages/storybook/src/generators/configuration/schema.json
Expand Up @@ -35,6 +35,10 @@
"enum": ["eslint", "tslint", "none"],
"default": "eslint"
},
"projectBuildConfig": {
"description": "Provide a custom projectBuildConfig for the Angular executor. If left blank, Nx will use the default.",
"type": "string"
},
"js": {
"type": "boolean",
"description": "Generate JavaScript files rather than TypeScript files.",
Expand Down

1 comment on commit 9579aec

@vercel
Copy link

@vercel vercel bot commented on 9579aec Apr 5, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.