question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Angular: global style entry points are bundled into JS instead of separate CSS files

See original GitHub issue

Describe the bug Honestly, this is one of those things where it seems so obviously an issue that I am half expecting you to tell me I am misunderstanding 😅

As you know, in angular.json you provide "styles": [] on your project - these are global entry points and when you run ng build they will be spat out as individual CSS files via the webpack build.

When building storybook, however, even though I can see it is using angular devkit’s webpack config for styles behind the scenes, it does not respect this and instead bundles the global CSS files into JS bundles. This is definitely not what I want.

To Reproduce

I created a brand new Nx workspace from scratch using the angular preset and simply added storybook, nothing else is needed: https://github.com/JamesHenry/storybook-test

To reproduce, simply compare the relevant dist entries after running nx build vs nx build-storybook.

System

 System:
    OS: macOS 11.4
    CPU: (8) x64 Apple M1
  Binaries:
    Node: 14.17.0 - ~/.volta/tools/image/node/14.17.0/bin/node
    Yarn: 1.22.10 - ~/.volta/tools/image/yarn/1.22.10/bin/yarn
    npm: 7.12.1 - ~/.volta/tools/image/npm/7.12.1/bin/npm
  Browsers:
    Safari: 14.1.1
  npmPackages:
    @storybook/angular: ^6.2.7 => 6.3.0 
    @storybook/builder-webpack5: ^6.2.7 => 6.3.0 
    @storybook/manager-webpack5: ^6.3.0 => 6.3.0 

Additional context

If you end up telling me this is the intended behaviour in storybook, then please provide some guidance on how I can work around it. I have a use-case where I very much need to spit out individual global CSS files (client-based theming).

Issue Analytics

  • State:open
  • Created 2 years ago
  • Comments:8 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
JamesHenrycommented, Jun 28, 2021

@ThibaudAV Allow me to break it all down, hopefully that will help:

How and why the Angular CLI build piece works

  • The application, let’s call it my-app is developed by a company for several clients/customers who have their own theme for the application which is appropriate for their brand - logos, colour differences etc. Therefore things need to be developed in such a way that not all the possible styles are included in every deployment of the application.

  • We therefore definitely do not want a theming approach based on toggling a class because that implies shipping all possible CSS to all possible deployments.

  • The Angular CLI has a "styles" configuration property on projects which allows you to specify global entrypoints in your webpack compilation.

Here is an anonymized example of real configuration:

image

  • Thanks to the Angular CLI’s webpack configuration, these entrypoints end up as .css files when you build the app, they are not wrapped in JS bundles.

image

This is exactly what we want.

apps/my-app/src/styles.scss -> styles.css The global foundational styles of the application that are always present/required. This file is injected into the index.html automatically by the Angular CLI.

libs/shared/client-configuration/src/lib/default/styles.scss -> styles-default.css libs/shared/client-configuration/src/lib/foo/styles.scss -> styles-foo.css libs/shared/client-configuration/src/lib/bar/styles.scss -> styles-bar.css The theming-specific styles (colours etc) of the application that are differentiated per client/customer deployment (“default” is just a default theme for customers that don’t want any customizations). These files are not injected into the HTML markup automatically (thanks to "inject": false) and will be included by us only where appropriate for a particular client/customer deployment. E.g. styles-bar.css will never be used for the customer called “foo”.


Relevance and issue with Storybook

  • When developing components for this and the other client-themed applications in Storybook, we naturally want to be able toggle the client theme we are working on from time to time so that we can see the realistic end results of our work.

  • I therefore created a very simple Storybook toolbar add-on (thanks for making this so easy to achieve) which is a dropdown of client/theme names which on change ultimately swaps in a <link> tag with the appropriate stylesheet for the selected theme. It works great - so far, so good!

  • However, the reason for reporting this issue is down to when it comes to serving and building Storybook - for some reason Storybook is changing the behaviour of the Angular CLI’s resolved webpack configuration somewhere internally because instead of producing .css files from the above "styles" config, it is wrapping all the global CSS sources in JS bundles.

  • The only way we can work around this currently is to build the full application first, then serve or build storybook while pointing it to the dist of the app as a static dir. Naturally, this is very inefficient and will only get worse as the application grows!

  • I have not been able to think of a reason why you would need to change the Angular CLI’s logic in this regard to make Storybook work, so hopefully this is something which can be amended.


Hopefully everything is clear now, please let me know if not. If we can adjust the logic within Storybook Angular so that it stops overriding the Angular CLI’s webpack config in this regard then this issue will be resolved.

0reactions
JamesHenrycommented, Aug 2, 2021

@ThibaudAV

Why not either do :

  • several projects (one per client configuration) in angular.json
  • or several configurations and use the fileReplacements or styles to complete, override those by default

The application is functionally the same - building it multiple times (which both of these suggestions imply) is definitely not desirable even if there were only 2 clients and it were not much extra time (in our case, however, there are many more than two so from a time perspective it does not scale well at all). We should be building once, deploying N times. In our case which theme css file to package with the app is a deployment-time concern.

Just to update everyone here, what I ended up doing was building a completely custom (therefore I’m afraid unshareable) Angular CLI builder/Nx executor) in order to just compile the style files using the same kind of angular-devkit webpack styles resolution which storybook does internally. I run that builder just before storybook runs and point storybook to the compiled css files as a --static-dir. I then have a custom storybook toolbar add-on to allow me to switch to a different theme file in the storybook UI when it runs.

Again, apologies I will not be able to share any of this as it is under a consultancy contract, so please don’t ask 😅

FWIW @ThibaudAV, even though the type information in angular-devkit did not agree, the only significant thing I had to do on top of your existing storybook logic was to add extractCss: true to the buildOptions property of the object you pass to getStylesConfig(...).

I found this simply by looking at the angular-devkit source by seeing what it used to determine if it should produce css files or js files for styles.

Hope that helps!

Read more comments on GitHub >

github_iconTop Results From Across the Web

This is how angular-cli/webpack delivers your CSS styles to ...
Angular -CLI loads these styles as a separate bundle to the client. So we will do the same. Webpack creates bundles based on...
Read more >
Keeping CSS out of JS in Angular 2/Angular-CLI
It's easy to track down css style sheets of a component....just find what styleUrls point to or add them under styles. As long...
Read more >
Dynamically Load CSS with the Angular CLI | juri.dev
Create various style entry points. First of all, we need to create the various entry point CSS files of course. You can just...
Read more >
Component styles - Angular
Additionally, Angular can bundle component styles with components, ... This includes ::ng-deep , which promotes a component style to a global style.
Read more >
Code Splitting - webpack
Entry Points : Manually split code using entry configuration. ... As you can see there's another runtime.bundle.js file generated besides shared.bundle.js ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found