Skip to content

Conversation

@kroeder
Copy link
Member

@kroeder kroeder commented Aug 14, 2025

Closes #32105

What I did

Merging builder options and browser target options now properly only merges explicitly set properties.

Before, the code relied on an object that got populated by Angular and contained every property available.
If user-land has not defined, e.g. styles: ["something"], then Angular has set the value to styles: []
This caused an auto-overwrite of the browser target options.

The new behavior only overwrites browser target options, if user-land explicitly has set builder options

Checklist for Contributors

Testing

For me, looking at the existing test cases, it was hard to write a test that provides actual confidence. However I tried it, I had to mock it in a way that would end up in a false confidence.

It would be nice if someone could help me out with that.

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

Verify it does load styles from the browserTarget

  1. Create an Angular sandbox project
  2. Check that angular.json does not contain styles: [] for the storybook target
  3. Modify "styles.scss" to contain e.g. button { display: none !important; }
  4. Run the sandbox and navigate to a button story -> it should load the styles from browserTarget, therefore the button is now invisible

Verify it's possible to overwrite the styles in the builder options

  1. Create an Angular sandbox project
  2. Check that angular.json contains e.g. styles: ["src/test.scss"] for the storybook target
  3. Create and mofify "src/test.scss" to contain e.g. button { display: none !important; }
  4. Run the sandbox and navigate to a button story -> it should load the styles from the builder options, therefore the button is now invisible

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This PR does not have a canary release associated. You can request a canary release of this pull request by mentioning the @storybookjs/core team here.

core team members can create a canary release here or locally with gh workflow run --repo storybookjs/storybook canary-release-pr.yml --field pr=<PR_NUMBER>

Greptile Summary

This PR fixes a critical bug in the Angular framework integration where Storybook's builder options were incorrectly overriding browser target configurations. The issue occurred because Angular pre-populates options.angularBuilderOptions with default values for all possible properties (e.g., styles: [] even when users haven't explicitly set styles), causing unintended overwrites of browser target settings.

The fix changes the merging logic in framework-preset-angular-cli.ts to use explicitAngularBuilderOptions obtained directly from builderContext.getTargetOptions() instead of the pre-populated options.angularBuilderOptions. This ensures that only explicitly user-defined options override browser target settings, preserving the expected inheritance behavior where Storybook configurations should inherit from the specified browserTarget unless explicitly overridden.

This change is part of the Angular framework's webpack configuration setup, which is responsible for merging build options from different sources. The modification maintains backward compatibility while restoring the correct precedence order: browser target options serve as defaults, and only explicitly defined Storybook builder options override them. This addresses a regression that affected styles, assets, and stylePreprocessorOptions inheritance from browserTarget configurations.

Confidence score: 4/5

  • This fix addresses a well-defined regression with a targeted solution that preserves existing behavior
  • The change is minimal and focused, reducing the risk of introducing new issues
  • Manual testing steps are provided to verify both inheritance and override scenarios work correctly

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

1 file reviewed, no comments

Edit Code Review Bot Settings | Greptile

@nx-cloud
Copy link

nx-cloud bot commented Aug 14, 2025

View your CI Pipeline Execution ↗ for commit 3575e12

Command Status Duration Result
nx run-many -t build --parallel=3 ✅ Succeeded 43s View ↗

☁️ Nx Cloud last updated this comment at 2025-08-28 09:58:10 UTC

@kroeder kroeder changed the title fix(angular): properly merge storybook and browserTarget options Angular: Properly merge builder options and browserTarget options Aug 14, 2025
@storybook-app-bot
Copy link

storybook-app-bot bot commented Aug 14, 2025

Package Benchmarks

Commit: 3575e12, ran on 28 August 2025 at 09:45:24 UTC

No significant changes detected, all good. 👏

@valentinpalkovic valentinpalkovic self-assigned this Aug 18, 2025

expect(mockedTargetFromTargetString).not.toHaveBeenCalled();
expect(mockBuilderContext.getTargetOptions).not.toHaveBeenCalled();
expect(mockBuilderContext.getTargetOptions).toHaveBeenCalledOnce();
Copy link
Member Author

Choose a reason for hiding this comment

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

fyi: since we now also use getTargetOptions for retrieving the builder options, it is always called once, and if theres a browserTarget, called twice

@kroeder
Copy link
Member Author

kroeder commented Aug 21, 2025

@valentinpalkovic I fixed the failing tests and CI is now green 🙂

@kroeder
Copy link
Member Author

kroeder commented Aug 22, 2025

@valentinpalkovic I just merged next into this branch and now, for the second time, a test runs into a timeout... is this a flacky test on main?

@valentinpalkovic
Copy link
Contributor

Seems to be flaky. Let's rerun it.

@valentinpalkovic valentinpalkovic added the patch:yes Bugfix & documentation PR that need to be picked to main branch label Aug 22, 2025
@kroeder
Copy link
Member Author

kroeder commented Aug 27, 2025

Is there anything I can do to help getting this merged? We currently use a workaround in our Storybook and I would love to remove that

@angelnikolov
Copy link

@kroeder I somehow found this PR after several hours of debugging the same issue.. Can you share what the workaround was so I can test it in our workspace while this gets merged?

@kroeder
Copy link
Member Author

kroeder commented Aug 28, 2025

@kroeder I somehow found this PR after several hours of debugging the same issue.. Can you share what the workaround was so I can test it in our workspace while this gets merged?

@angelnikolov copy over everything you need from the "browserTarget" to the actual target

The problem this PR fixes is that if you don't set anything in the actual builder options, it initializes itself with an empty array/object. Therefore, you always overwrite what you would originally get from browserTarget

Example:

// this is broken
{
  "serve": {
    "executor": "@storybook/angular:start-storybook",
      "options": {
        "browserTarget": "storybook:build-storybook"
        // ...
      }
    }
  },
  "build-storybook": {
    "executor": "@storybook/angular:build-storybook",
      "options": {
        "styles": ["styles.scss"]
        // ...
      }
    }
  },
}

should be this

// this works
{
  "serve": {
    "executor": "@storybook/angular:start-storybook",
      "options": {
        "browserTarget": "storybook:build-storybook",
        "styles": ["styles.scss"]
        // ...
      }
    }
  },
  "build-storybook": {
    "executor": "@storybook/angular:build-storybook",
      "options": {
        "styles": ["styles.scss"]
        // ...
      }
    }
  },
}

@angelnikolov
Copy link

That was quick! Thanks!

@valentinpalkovic valentinpalkovic merged commit f739234 into next Aug 29, 2025
55 checks passed
@valentinpalkovic valentinpalkovic deleted the kroeder/angular-config-merge-bug branch August 29, 2025 21:20
ndelangen pushed a commit that referenced this pull request Sep 2, 2025
…ge-bug

Angular: Properly merge builder options and browserTarget options
(cherry picked from commit f739234)
@github-actions github-actions bot added the patch:done Patch/release PRs already cherry-picked to main/release branch label Sep 2, 2025
@ndelangen ndelangen removed the patch:yes Bugfix & documentation PR that need to be picked to main branch label Oct 28, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

angular bug ci:normal patch:done Patch/release PRs already cherry-picked to main/release branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Angular + Webpack not picking up styles, assets and stylePreprocessorOptions from browserTarget after update to version 9.

5 participants