Skip to content

Commit

Permalink
feat(storybook): use native storybook/angular executor (#9332)
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed May 19, 2022
1 parent 4863e51 commit 51b66d1
Show file tree
Hide file tree
Showing 35 changed files with 1,543 additions and 895 deletions.
21 changes: 21 additions & 0 deletions docs/generated/packages/angular.json
Expand Up @@ -2032,6 +2032,27 @@
"aliases": [],
"hidden": false,
"path": "/packages/angular/src/generators/web-worker/schema.json"
},
{
"name": "change-storybook-targets",
"factory": "./src/generators/change-storybook-targets/change-storybook-targets",
"schema": {
"$schema": "http://json-schema.org/schema",
"$id": "NxAngularChangeStorybookTargetsGenerator",
"title": "Change Storybook targets",
"description": "Change the Storybook target executors.",
"type": "object",
"cli": "nx",
"properties": {},
"additionalProperties": false,
"required": [],
"presets": []
},
"description": "Change storybook targets for Angular projects to use @storybook/angular executors",
"implementation": "/packages/angular/src/generators/change-storybook-targets/change-storybook-targets.ts",
"aliases": [],
"hidden": false,
"path": "/packages/angular/src/generators/change-storybook-targets/schema.json"
}
],
"executors": [
Expand Down
93 changes: 22 additions & 71 deletions docs/generated/packages/storybook.json

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions docs/packages.json
Expand Up @@ -44,7 +44,8 @@
"stories",
"storybook-configuration",
"upgrade-module",
"web-worker"
"web-worker",
"change-storybook-targets"
]
}
},
Expand Down Expand Up @@ -243,7 +244,12 @@
"path": "generated/packages/storybook.json",
"schemas": {
"executors": ["storybook", "build"],
"generators": ["init", "configuration", "cypress-project"]
"generators": [
"init",
"configuration",
"cypress-project",
"change-storybook-targets"
]
}
},
{
Expand Down
83 changes: 36 additions & 47 deletions docs/shared/guides/storybook/plugin-angular.md
Expand Up @@ -188,91 +188,80 @@ describe('shared-ui', () => {
});
```

### Setting up `projectBuildConfig`
### Storybook uses `browserTarget` for Angular

Storybook for Angular needs a default project specified in order to run. The reason is that it uses that default project to read the build configuration from (paths to files to include in the build, and other configurations/settings). In Nx workspaces, that project is specified with the `projectBuildConfig` property.

If you're using Nx version `>=13.4.6` either in a new Nx workspace, or you migrated your older Nx workspace to Nx version `>=13.4.6`, Nx will automatically add the `projectBuildConfig` property in your projects `project.json` files, for projects that are using Storybook. It will look like this:
Nx is using the original Storybook executor for Angular to serve and build Storybook. If you're using Storybook in
your Angular project, you will notice that `browserTarget` is specified for the `storybook` and `build-storybook` targets, much like it is done for `serve` or other targets. Angular needs the `browserTarget` for Storybook in order to know which configuration to use for the build. If your project is buildable (it has a `build` target, and uses the main Angular builder - `@angular-devkit/build-angular:browser`) the `browserTarget` for Storybook will use the `build` target, if it's not buildable it will use the `build-storybook` target.

```json
"storybook": {
"executor": "@nrwl/storybook:storybook",
"executor": "@storybook/angular:start-storybook",
"options": {
...
"projectBuildConfig": "my-project:build-storybook"
"browserTarget": "my-project:build"
},
...
},
"build-storybook": {
"executor": "@nrwl/storybook:build",
"executor": "@storybook/angular:build-storybook",
...
"options": {
...
"projectBuildConfig": "my-project:build-storybook"
"browserTarget": "my-project:build"
},
...
}
```

This setup instructs Nx to use the configuration under the `build-storybook` target of `my-project` when using the `storybook` and `build-storybook` executors.

If the `projectBuildConfig` is not set in your `project.json`, you can manually set it up in one of the following ways:

#### Adding the `projectBuildConfig` option directly in the project's `project.json`

In your project's `project.json` file find the `storybook` and `build-storybook` targets. Add the `projectBuildConfig` property under the `options` as shown above.

After you add this property, you can run your `storybook` and `build-storybook` executors as normal:

```bash
nx storybook my-project
```

and

```bash
nx build-storybook my-project
```

#### Using the `projectBuildConfig` flag on the executors

The way you would run your `storybook` and your `build-storybook` executors would be:

```bash
nx storybook my-project --projectBuildConfig=my-project:build-storybook
```

and

```bash
nx build-storybook my-project --projectBuildConfig=my-project:build-storybook
```

**Note:** If your project is buildable (eg. any project that has a `build` target set up in its `project.json`) you can also do `nx storybook my-project --projectBuildConfig=my-project`.

> In a pure Angular/Storybook setup (**not** an Nx workspace), the Angular application/project would have an `angular.json` file. That file would have a property called `defaultProject`. In an Nx workspace the `defaultProject` property would be specified in the `nx.json` file. Previously, Nx would try to resolve the `defaultProject` of the workspace, and use the build configuration of that project. In most cases, the `defaultProject`'s build configuration would not work for some other project set up with Storybook, since there would most probably be mismatches in paths or other project-specific options.
This setup instructs Nx to use the configuration under the `build` target of `my-project` when using the `storybook` and `build-storybook` executors.

### Configuring styles and preprocessor options

Angular supports including extra entry-point files for styles. Also, in case you use Sass, you can add extra base paths that will be checked for imports. In your project's `project.json` file you can use the `styles` and `stylePreprocessorOptions` properties in your `storybook` and `build-storybook` target `options`, as you would in your Storybook or your Angular configurations. Check out the [Angular Workspace Configuration](https://angular.io/guide/workspace-config#styles-and-scripts-configuration) documentation for more information.

```json
"storybook": {
"executor": "@nrwl/storybook:storybook",
"executor": "@storybook/angular:start-storybook",
"options": {
...
"styles": ["some-styles.css"],
"stylePreprocessorOptions": {
"includePaths": ["some-style-paths"]
}
},
...
},
"build-storybook": {
"executor": "@storybook/angular:build-storybook",
...
"options": {
...
"styles": ["some-styles.css"],
"stylePreprocessorOptions": {
"includePaths": ["some-style-paths"]
}
},
...
}
```

> **Note**: Chances are, you will most probably need the same `styles` and `stylePreprocessorOptions` for your `storybook` and your `build-storybook` targets. Since you're using `browserTarget`, that means that Storybook will use the `options` of `build` or `build-storybook` when executing the `storybook` task (when compiling your Storybook). In that case, you _only_ need to add the `styles` or `stylePreprocessorOptions` to the corresponding target (`build` or `build-storybook`) that the `browserTarget` is pointing to. In that case, for example, the configuration shown above would look like this:
```json
"storybook": {
"executor": "@storybook/angular:start-storybook",
"options": {
...
"browserTarget": "my-project:build-storybook"
},
...
},
"build-storybook": {
"executor": "@nrwl/storybook:build",
"executor": "@storybook/angular:build-storybook",
...
"options": {
...
"browserTarget": "my-project:build-storybook",
"styles": ["some-styles.css"],
"stylePreprocessorOptions": {
"includePaths": ["some-style-paths"]
Expand Down
11 changes: 11 additions & 0 deletions packages/angular/generators.json
Expand Up @@ -148,6 +148,12 @@
"factory": "./src/generators/web-worker/compat",
"schema": "./src/generators/web-worker/schema.json",
"description": "Creates a Web Worker."
},
"change-storybook-targets": {
"factory": "./src/generators/change-storybook-targets/compat",
"schema": "./src/generators/change-storybook-targets/schema.json",
"description": "Change storybook targets for Angular projects to use @storybook/angular executors",
"hidden": false
}
},
"generators": {
Expand Down Expand Up @@ -298,6 +304,11 @@
"factory": "./src/generators/web-worker/web-worker",
"schema": "./src/generators/web-worker/schema.json",
"description": "Creates a Web Worker."
},
"change-storybook-targets": {
"factory": "./src/generators/change-storybook-targets/change-storybook-targets",
"schema": "./src/generators/change-storybook-targets/schema.json",
"description": "Change storybook targets for Angular projects to use @storybook/angular executors"
}
}
}
1 change: 1 addition & 0 deletions packages/angular/generators.ts
Expand Up @@ -22,3 +22,4 @@ export * from './src/generators/component-cypress-spec/component-cypress-spec';
export * from './src/generators/component-story/component-story';
export * from './src/generators/web-worker/web-worker';
export * from './src/generators/remote/remote';
export * from './src/generators/change-storybook-targets/change-storybook-targets';
@@ -0,0 +1,8 @@
import type { Tree } from '@nrwl/devkit';
import { changeStorybookTargetsGenerator } from '@nrwl/storybook';

export async function angularChangeStorybookTargestGenerator(tree: Tree) {
await changeStorybookTargetsGenerator(tree);
}

export default angularChangeStorybookTargestGenerator;
@@ -0,0 +1,4 @@
import { convertNxGenerator } from '@nrwl/devkit';
import angularChangeStorybookTargestGenerator from './change-storybook-targets';

export default convertNxGenerator(angularChangeStorybookTargestGenerator);
@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/schema",
"$id": "NxAngularChangeStorybookTargetsGenerator",
"title": "Change Storybook targets",
"description": "Change the Storybook target executors.",
"type": "object",
"cli": "nx",
"properties": {},
"additionalProperties": false,
"required": []
}
12 changes: 12 additions & 0 deletions packages/storybook/generators.json
Expand Up @@ -20,6 +20,12 @@
"schema": "./src/generators/cypress-project/schema.json",
"description": "Add cypress e2e app to test a UI library that is set up for Storybook.",
"hidden": false
},
"change-storybook-targets": {
"factory": "./src/generators/change-storybook-targets/change-storybook-targets#changeStorybookTargetsSchematic",
"schema": "./src/generators/change-storybook-targets/schema.json",
"description": "Change storybook targets for Angular projects to use @storybook/angular executors",
"hidden": false
}
},
"generators": {
Expand All @@ -41,6 +47,12 @@
"schema": "./src/generators/cypress-project/schema.json",
"description": "Add cypress e2e app to test a UI library that is set up for Storybook.",
"hidden": false
},
"change-storybook-targets": {
"factory": "./src/generators/change-storybook-targets/change-storybook-targets",
"schema": "./src/generators/change-storybook-targets/schema.json",
"description": "Change storybook targets for Angular projects to use @storybook/angular executors",
"hidden": false
}
}
}
1 change: 1 addition & 0 deletions packages/storybook/index.ts
@@ -1,3 +1,4 @@
export { configurationGenerator } from './src/generators/configuration/configuration';
export { cypressProjectGenerator } from './src/generators/cypress-project/cypress-project';
export { changeStorybookTargetsGenerator } from './src/generators/change-storybook-targets/change-storybook-targets';
export { storybookVersion } from './src/utils/versions';
6 changes: 6 additions & 0 deletions packages/storybook/migrations.json
Expand Up @@ -84,6 +84,12 @@
"cli": "nx",
"description": "Migrate Storybook to v6",
"factory": "./src/migrations/update-14-0-0/migrate-to-storybook-6"
},
"update-14.1.8": {
"version": "14.1.8",
"cli": "nx",
"description": "Change storybook targets for Angular projects to use @storybook/angular executors",
"factory": "./src/migrations/update-14-1-8/change-storybook-targets"
}
},
"packageJsonUpdates": {
Expand Down
@@ -1,5 +1,4 @@
import { ExecutorContext, logger } from '@nrwl/devkit';

import { join } from 'path';
jest.mock('@storybook/core/standalone', () =>
jest.fn().mockImplementation(() => Promise.resolve())
Expand All @@ -17,7 +16,7 @@ describe('Build storybook', () => {
let config: StorybookBuilderOptions['config'];

beforeEach(async () => {
uiFramework = '@storybook/angular';
uiFramework = '@storybook/react';
outputPath = '/root/dist/storybook';
config = {
pluginPath: join(
Expand All @@ -36,11 +35,6 @@ describe('Build storybook', () => {
options = {
uiFramework,
outputPath,
projectBuildConfig: 'proj',
stylePreprocessorOptions: {
includePaths: ['my-path/my-style-options'],
},
styles: ['my-other-path/my-other-styles.scss'],
config,
};

Expand All @@ -57,12 +51,22 @@ describe('Build storybook', () => {
sourceRoot: 'src',
targets: {
build: {
executor: '@angular-devkit/build-angular:browser',
executor: '@nrwl/web:webpack',
options: {
main: 'apps/proj/src/main.ts',
outputPath: 'dist/apps/proj',
tsConfig: 'apps/proj/tsconfig.app.json',
index: 'apps/proj/src/index.html',
compiler: 'babel',
outputPath: 'dist/apps/webre',
index: 'apps/webre/src/index.html',
baseHref: '/',
main: 'apps/webre/src/main.tsx',
polyfills: 'apps/webre/src/polyfills.ts',
tsConfig: 'apps/webre/tsconfig.app.json',
assets: [
'apps/webre/src/favicon.ico',
'apps/webre/src/assets',
],
styles: ['apps/webre/src/styles.css'],
scripts: [],
webpackConfig: '@nrwl/react/plugins/webpack',
},
},
storybook: {
Expand All @@ -72,7 +76,6 @@ describe('Build storybook', () => {
},
},
},
defaultProject: 'proj',
npmScope: 'test',
},
isVerbose: false,
Expand Down
Expand Up @@ -4,7 +4,6 @@ import 'dotenv/config';
import { CommonNxStorybookConfig } from '../models';
import {
getStorybookFrameworkPath,
normalizeAngularBuilderStylesOptions,
resolveCommonStorybookOptionMapper,
runStorybookSetupCheck,
} from '../utils';
Expand All @@ -24,7 +23,6 @@ export default async function buildStorybookExecutor(
const frameworkPath = getStorybookFrameworkPath(options.uiFramework);
const { default: frameworkOptions } = await import(frameworkPath);

options = normalizeAngularBuilderStylesOptions(options, options.uiFramework);
const option = storybookOptionMapper(options, frameworkOptions, context);

// print warnings
Expand Down
4 changes: 0 additions & 4 deletions packages/storybook/src/executors/models.ts
Expand Up @@ -16,9 +16,5 @@ export interface CommonNxStorybookConfig {
| '@storybook/svelte'
| '@storybook/react-native';
projectBuildConfig?: string;
styles?: any[];
stylePreprocessorOptions?: {
includePaths?: string[];
};
config: StorybookConfig;
}

1 comment on commit 51b66d1

@vercel
Copy link

@vercel vercel bot commented on 51b66d1 May 19, 2022

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

nx-dev – ./

nx-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.