I think it could be useful to have an Angular-Cli builder provided by storybook.
Then in angular.json, we could just do:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"projects": {
"storybook": {
"root": "projects/storybook",
"sourceRoot": "projects/storybook/src",
"projectType": "application",
"architect": {
"build": {
"builder": "@storybook/storybook-builder:build",
"options": {
"outputPath": "dist/projects/.out",
"tsConfig": "projects/storybook/tsconfig.app.json",
"assets": [
"projects/storybook/favicon.ico",
"projects/storybook/assets"
],
"styles": [
"libs/core/theme.scss",
"projects/storybook/styles.scss"
]
}
},
"serve": {
"builder": "@storybook/storybook-builder:dev-server",
"options": {
"browserTarget": "storybook:build"
}
},
"test": {
"builder": "@storybook/storybook-builder:test",
"options": {
"browserTarget": "storybook:build",
"tsConfig": "projects/storybook/tsconfig.spec.json",
}
}
}
}
}
}
Improvements:
angular.json from storybookng serve storybook or ng build storybook or ng test storybookangular.json application. In my case, storybook help me to test many libraries declared in angular.json`.More infos: Customizing Angular CLI 6 build — an alternative to ng eject
Tasks to get there:
@storybook/angular:start: tsConfig, port, host, staticDirs, configDir, quiet@storybook/angular:build: tsConfig, host, staticDirs, outputDir, configDir, watch@storybook/angular:build and include the storybook/app/angular/server functionalitiestsConfig option to get typescript configurations instead of default tsconfig in the configDirbuilder options:@angular/cli webpack configs@storybook/angular:build to create the builder @storybook/angular:start@storybook/angular:test to run tests in storybookstorybook/app/angular/server by the builderstorybook/examples/angular-cli@angular-builders/jeststorybook/lib/cli/generators/ANGULAR to inject storybook project with builders in angular.jsonLater improvments:
storybook/app/angular/client functionalities (!!! don't know yet the faisability)config.ts file:tsconfig instead of a method in confaddons in the builder specwebpackConfig in the builder specInteresting suggestion. It can definitely be a package in the storybook org. Would you like to PR this?
@igor-dv I started to have a look but to be honest, I am not an expert of storybook and I just started to understand how @storybook/angular is working with a client and a server. I am not at all an expert in webpack ;).
I'll try to make a small repo with a builder that could cover what the @storybook/angular/server is doing today. Then I'll probably need helps to integrate that in the storybook repository.
Sure, LMK if you need something, also we have a slack
I didn't really progress on the builders...I don't have a lot of time and not a 'builder/webpack' guy so I have some technicals issues...
But I had time to analyze and think about the list of tasks needed to make the builders, so I updated the ticket description. If anyone has any other ideas, do not hesitate to tell me and I will add them.
@igor-dv
I simply made a builder that reflect the existing code in storybook/app/angular/serve:
import { Builder, BuilderConfiguration, BuilderContext, BuildEvent } from '@angular-devkit/architect';
import { from, Observable, of } from 'rxjs';
import { map, tap } from 'rxjs/operators';
import { StartStorybookSchema } from './schema';
import { buildDev } from '@storybook/core/server';
import storyBookOptions from '@storybook/angular/dist/server/options';
export default class StartStorybookBuilder implements Builder<StartStorybookSchema> {
constructor(private context: BuilderContext) {}
run(builderConfig: BuilderConfiguration<Partial<StartStorybookSchema>>): Observable<BuildEvent> {
console.log('OK');
return of(null).pipe(
tap(_ => buildDev(storyBookOptions)),
map(() => ({ success: true }))
);
}
}
But when I run it I have this issue:
Cannot find module '@babel/plugin-proposal-class-properties'
Error: Cannot find module '@babel/plugin-proposal-class-properties'
at Function.Module._resolveFilename (module.js:547:15)
at Function.resolve (internal/module.js:18:19)
at Object.<anonymous> (/mnt/c/Users/jo/dev/build-storybook/example/node_modules/@storybook/core/dist/server/config/babel.js:13:117)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
Why do I need to add this dependency in my project ? Isn't a dependency provided by storybook ?
Another question for my info, what is the differences between wrapInitialConfig, wrapDefaultConfig and wrapBasicConfig ? Why storybook needs these 3 configurations ? Why don't we merge all configs in the initial ?
This issue was solved today https://github.com/storybooks/storybook/releases/tag/v4.0.0-alpha.18
Small update to avoid deletion of the issue ;)
Repository of the POC: https://github.com/jogelin/storybook-builders
Next step: integrate in the storybook repository to see how could we build the builders and update the core that could match the builders "way"
Is this still on the roadmap ?
For anyone that's looking for an Angular 6+ builder. They a PR which been placed for NX which contains a storybook builder. The builder is also cross platform so would work in mono-repo and micro frontends
https://github.com/nrwl/nx/pull/1582
"storybook": {
"builder": "@nrwl/storybook:storybook",
"options": {
"uiFramework": "@storybook/angular",
"config": {
"configFolder": "apps/rina-eas/.storybook"
}
}
}
It has other config options such as the path to tsconfig etc. Will try and build it out more if you have suggestions
@igor-dv I have created such a builder as a standalone package, but if you're interested I'd be happy to convert it into a PR in this repo.
I've also created an Angular schematic to install the builder via ng add and generate stories (currently only CSF) along with components.
It works with Angular 10/Storybook 6, but should be backwards compatible to Angular 8 (when the builder API was released). Have a look at it here, try it, and let me know.
cc @Marklb @kroeder @gaetanmaisse what do you guys think?
I like the idea of providing a builder, since it fits more naturally with Angular's configuration. The main users I could see it benefiting are the ones with multiple projects that they want to have an independent storybook build for.
I can't think of a reason Storybook should add a builder for any of Angular's targets, such as build, serve, test, etc, because Storybook is not meant to replace their functionality. The exception may be a project that is only for Storybook and builds a single Storybook with all the projects stories, maybe a builder that outputs a build that is configured to compose all the individual projects with Storybooks using Storybook's Composition.
What I think would be useful is a storybook and build-storybook builder that could be added as their own targets. That way each project could configure Storybook without interfering with any Angular targets. I have never used a custom target myself, but from Angular's docs it looks like it's mainly just a matter of configuring it. Adding a target This issue may have already been considering this, but my interpretation was that this builder would be used in the build target.
I have never used Nx, but from the few repos I have looked at that use Nx, it looks like their schematics configure the projects with
storybookandbuild-storybooktargets like this.
I don't have anything to add to the target's configuration, that hasn't already been mentioned, but an example of what I would expect the angular.json configuration to look like with @storybook/storybook-builder:* builders would be the following:
{
"projects": {
"example-app": {
"projectType": "application",
"root": "projects/example-app",
"sourceRoot": "projects/example-app/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": { ... }
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": { ... }
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": { ... }
},
"storybook": {
"builder": "@storybook/build-storybook:dev-server",
"options": { ... }
},
"build-storybook": {
"builder": "@storybook/build-storybook:build",
"options": { ... }
},
}
},
"example-lib": {
"projectType": "library",
"root": "projects/example-lib",
"sourceRoot": "projects/example-lib/src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
"options": { ... }
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": { ... }
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": { ... }
},
"storybook": {
"builder": "@storybook/build-storybook:dev-server",
"options": { ... }
},
"build-storybook": {
"builder": "@storybook/build-storybook:build",
"options": { ... }
},
}
},
// I am still deciding if something like this one would even be worth it.
"composed-sb-docs": {
"projectType": "application",
"root": "projects/composed-sb-docs",
"sourceRoot": "projects/composed-sb-docs/src",
"prefix": "app",
"architect": {
"storybook": {
"builder": "@storybook/build-storybook:dev-server-composed",
"options": { ... }
},
"build-storybook": {
"builder": "@storybook/build-storybook:build-composed",
"options": { ... }
},
}
},
},
"schematics": {
"@storybook/angular:application": { ... },
"@storybook/angular:library": { ... }
},
}
Even though this issue is about builders, I like the use of schematics in @cmurczek's package. I have some simple VSCode snippets for stories that I sometimes use to scaffold the minor boilerplate in story files, but I have considered building schematics for them eventually.
I almost always run a schematic to generate my component files and immediately create a *.stories.ts file after. For building the generator command I normally use a VSCode extension that lists the options and it would be nice to have an option to have the generator create the *.stories.ts or *.stories.mdx file at the same time.
Not that it would affect the implementation, this is the extension I was talking about when I said that I choose the schematic inputs from a list.
The builder I created actually uses a custom target rather than replacing one of Angular's targets. I considered serve, but then figured that there might be cases where serving the actual app would be beneficial (e.g. manual testing). The benefit of overriding an Angular target would be that it could be invoked like ng serve app, whereas custom targets need a little quirkier syntax like ng run app:storybook.
Contrary to @jogelin's approach, my implementation builds on the way Storybook is currently configured, i.e. via the main.js and preview.js files. From the Angular dev's point of view it would indeed be preferable to have the settings directly in the options of the builder rather than in files on disk (especially when there are multiple projects with Storybook in an Angular workspace). However, moving the configuration there would need considerable refactoring of the storybook core server. In addition to the configuration via the main and preview files and their processing, the server would need to provide an API that accepts the settings and passes them to the relevant functions. If you decided to switch to a builder, the server and builder could be gradually refactored under the hood to get there.
Most helpful comment
This issue was solved today https://github.com/storybooks/storybook/releases/tag/v4.0.0-alpha.18