Describe the bug
Currently, the @storybook/angular
plugin is relying hardcoded on the build
target from the Angular Architect. This is a problem as it wants to collect the tsConfig information from the build target.
https://github.com/storybookjs/storybook/blob/next/app/angular/src/server/angular-cli_config.ts#L100
// https://github.com/storybookjs/storybook/blob/next/app/angular/src/server/angular-cli_config.ts#L100
const { options: projectOptions } = project.architect.build;
const normalizedAssets = normalizeAssetPatterns(
projectOptions.assets,
dirToSearch,
project.sourceRoot
);
const projectRoot = path.resolve(dirToSearch, project.root);
const tsConfigPath = path.resolve(dirToSearch, projectOptions.tsConfig) as Path;
You can not rely on the project options of the hardcoded build target to get the tsConfig as this will result in not finding a tsConfig if you have a build target that has not a tsConfig field.
As you can have a different builder for the architect build step for example:
"architect": {
"build": {
"builder": "@nrwl/workspace:run-commands",
"options": {
"parallel": true,
"commands": [
{
"command": "npx ng run my-app:build-frontend"
},
{
"command": "npx ng run my-app:build-server"
}
]
},
I want to specify storybook which target it should take in this case myapp:build-frontend
to get the tsConfig options out of it. Otherwise, it will result in the following Error:
[error] TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined
at validateString (internal/validators.js:117:11)
at Object.resolve (path.js:980:7)
at Object.getAngularCliWebpackConfigOptions (/.../node_modules/@storybook/angular/dist/server/angular-cli_config.js:99:39)
at Object.webpackFinal (/.../node_modules/@storybook/angular/dist/server/framework-preset-angular-cli.js:7:56)
at /.../node_modules/@storybook/core/dist/server/presets.js:261:72
For all who are running into the same issue it is a workaround to add into the first build step a tsConfig option.
Furthermore, the detection of the project inside the architect does not work really well.
As it is not really compatible with monorepo structures.
// https://github.com/storybookjs/storybook/blob/next/app/angular/src/server/angular-cli_config.ts#L74
let projectName;
const firstProjectName = Object.keys(projects)[0];
if (projects.storybook) {
projectName = 'storybook';
} else if (defaultProject && projects[defaultProject]) {
projectName = defaultProject;
} else if (projects[firstProjectName]) {
projectName = firstProjectName;
}
My Proposal to this solution would be providing for the angular package an angular builder that has all the information about the angular cli through the architect.
So If you like this idea I'm willing to contribute this โ> Could be a ng add @storybook/angular
schematic that sets up everything properly and enables having multiple storybook instances for a monorepo structure on app or lib level.
Hi @lukasholzer,
Storybook has a CLI but since it is framework agnostic it might be odd to offer a start-storybook --angular-project=project1
๐ค
If I understand you correctly then you propose that you can do start multiple Storybook projects inside your Angular mono-repo using ng serve storybook-project1
, ng serve storybook-project2
etc.?
Yea angular offers the opportunity to have multiple apps and libraries - https://angular.io/guide/file-structure#multiple-projects. Or https://nx.dev/angular that is specialized to provide a monorepo outlet even with storybook support. I think developers who are using storybook are working in big environments with a lot of different domains and monorepos.
Sample structure:
apps/
- app1
- app2
- app3
libs/
- lib1
- lib...52
So what you basically have is you can have multiple domains in a workspace this can lead to having a lot of different UIs and design systems that you want to call individually with storybook. Basically every lib or app can have a storybook integration.
In an angular world, you never use a different CLI as the angular CLI so what Nx is offering it provides the storybook layer for the angular CLI https://nx.dev/angular/plugins/storybook/builders/build.
The downside is that they only wrap the core standalone function https://github.com/nrwl/nx/blob/master/packages/storybook/src/builders/build-storybook/build-storybook.impl.ts#L71 to run storybook. So they have to rely on gathering the options by storybook if it would be configurable you could specify those things via the angular builder.
import * as build from '@storybook/core/standalone';
Those builders for the Angular CLI are basically pure functions that getting called with the options that are provided via a JSON schema. Then the function has to return {success: true}
or false if it fails. Inside there you can call everything what you want.
So using a platform independent way for the core is perfectly fine. But when it comes to I decide to install and use angular I would go with their conventions.
ng run my-lib:serve-storybook
or ng run my-otherlib:build-storybook
would be the way in an angular universe to call those builders.
I too think the Angular implementation of Storybook could benefit from this a lot. And I agree: Angular devs are used to use the Angular CLI for everything. Nrwl/Nx already implemented a couple of Storybook schematics just for Nx.
@ndelangen @shilman what do you think about this?
In general, all runnable applications "register" themself in the angular.json. By all I mean
There's no limit. The Angular Architect is framework agnostic. The Angular team wrote their own builders for the Architect to run Angular applications for example.
By default,
npx @storybook/cli init
should add a project to the angular.json
. We sort of having this feature already. You can add this to your angular.json
for example:
projects: {
"storybook": {
"styles": ["css-file.css", "scss-file.scss"]
"scripts": ["external-script.js"]
}
}
See https://github.com/storybookjs/storybook/blob/next/app/angular/src/server/angular-cli_config.ts#L75
The downside of the current implementation in a mono-repo environment is that it only supports one single configuration for all applications.
As a comfort utility (aka what Angular devs normally do when adding new things) we can add a schematic to @storybook/angular
that allows us to run this in an angular environment. (Optional, not related to the original issue but got mentioned here https://github.com/storybookjs/storybook/issues/11125#issuecomment-642527158)
// Would do the same as npx @storybook/cli init
ng add @storybook/angular
Add a builder that allows to have multiple storybooks inside one angular mono-repo
Here's how Angular project entries normally look like (stripped out everything that is not important)
"projects": {
"my-application": {
"projectType": "application",
"root": "projects/my-application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/my-application",
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "my-application:build"
},
"configurations": {
"production": {
"browserTarget": "my-application:build:production"
}
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
...
}
}
}
}
}
This is how a Storybook project entry could look like
"my-application:storybook": {
"projectType": "application",
"root": "projects/my-application",
"architect": {
"build": {
"builder": "@storybook/angular:browser",
"options": {
"outputPath": "dist/my-application-storybook",
"tsConfig": ".storybook/tsconfig.json",
"assets": [
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"serve": {
"builder": "@storybook/angular:serve",
}
}
}
This configuration + some additions to the current @storybook/angular
implementation allows an Angular mono-repo to run commands like
// this will run the angular project projects.my-application:storybook
// the builder is the important part in the configuration as this is the one running start-storybook for this particular directory
ng serve my-application:storybook
ng build my-application:storybook
TL;DR not possible, sorry ๐
@lukasholzer we are still on the same page, are we?
Yea we are on the same page โ exactly what I meant only your sketch of the angular.json is not completely correct. You cannot use :
for target names. But this is a small detail.
{
"my-application": {
"projectType": "application",
"root": "projects/my-application",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
...
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "my-application:build"
}
},
"storybook-build": {
"builder": "@storybook/angular:browser",
"options": {
"outputPath": "dist/my-application-storybook",
"tsConfig": ".storybook/tsconfig.json",
"assets": [
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
}
},
"storybook-serve": {
"builder": "@storybook/angular:serve",
"options": {
"buildTarget": "my-application:storybook-build"
}
}
}
}
}
You would run it then with ng run my-application:build-storybook
or ng run my-application:serve-storybook
.
So If you want to implement this approach I could help you with that, as it is my daily job, creating angular builders and setup for https://github.com/Dynatrace/barista ๐
@kroeder @lukasholzer this sounds reasonable to me!
@lukasholzer do you have time to make the first step and create a PR where we can continue the discussion? I can help you set things up in the repo ๐ you can join the storybook discord server or DM me on twitter if you want
@kroeder for sure would be a pleasure to contribute this โ Maybe I can spare some time on the weekend or next week to tackle this! Do you have a link to the discord channel?
Can you assign me the issue?
@lukasholzer sounds great!
Let's chat about the kick-off in Discord
https://discord.gg/E4CGPQ -> KaiR#5732
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
@kroeder sorry hadn't had the time yet. Will try next week to squeeze some time into :D
+1 This would really help my use case.
I'm trying to build an angular library and the builder for that @angular-devkit/build-ng-packagr:build
doesn't support assets
like the normal app builder does. This means I need to have a build configuration for running storybook and a separate one for actually bundling my library.
As a workaround I have some npm scripts that I'm using to modify the angular.json before running my command. Not very clean ๐ข
Hi everyone! Seems like there hasn't been much going on in this issue lately. If there are still questions, comments, or bugs, please feel free to continue the discussion. Unfortunately, we don't have time to get to every issue. We are always open to contributions so please send us a pull request if you would like to help. Inactive issues will be closed after 30 days. Thanks!
Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!
Most helpful comment
So If you want to implement this approach I could help you with that, as it is my daily job, creating angular builders and setup for https://github.com/Dynatrace/barista ๐