Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I include global styles (scss) once for all Storybook iframes? #6364

Closed
omaracrystal opened this issue Apr 1, 2019 · 71 comments
Closed

Comments

@omaracrystal
Copy link

Describe the bug
I have been trying multiple ways of incorporating global styles (scss) once for all Storybook Iframes and have been unsuccessful. There doesn't seem to be a clear concise way to do this.

To Reproduce
Attempts:

    • Import the global styles within each component.
    • Results: Styles are applied, but, multiple global.scss styles is repeated {story#} x times.
    • One place recommend creating a decorator for Storybook and apply the "global" css that way.
    • Result: would not work for what I'm trying to do (multiple styles, mixins, variables, etc) This only works for small CSS changes
    • In config under .storybook require('../libs/storybook/global-styles.scss'); within the loadStories function
    • Result: Nothing
    • Tried importing the global styles within the Storybook index.ts
    • Result: Nothing
    • Tried adding the global styles via angular.json file
      • Result: Nothing

Expected behavior
I would expect to be able to import Global (scss) files in one place so that can be applied to every Story's Iframe. Could there be a config setting I'm not aware of?

System:

  • OS: MacOS
  • Device: Macbook Pro 2015
  • Browser: Chrome
  • Framework: Angular
  • Addons: - [addon-centered, addon-viewport, addon-info]
  • Version: [^5.0.1]

Additional context
I am hoping that I am missing some configuration within storybook that would make this simple to resolve.

@kroeder
Copy link
Member

kroeder commented Apr 1, 2019

Try adding your global.scss File into angular.json

Check your defaultProject (there's a defaultProject property inside the json) and add it to the styles list

"styles": [
              "projects/your-cli-project/src/lib/styles/your-styles.scss"
            ],

I do it that way and it works just fine. Is that an option for you?

@stale
Copy link

stale bot commented Apr 22, 2019

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!

@stale stale bot added the inactive label Apr 22, 2019
@blemaire
Copy link

blemaire commented Apr 23, 2019

Hi @omaracrystal here is how I did it:
in the .storybook/config.jsfiles, add the import with the correct loaders inlined:

import '!style-loader!css-loader!sass-loader!./scss-loader.scss';

Then add/import all the styles you need in the scss-loader.scss file:

$font-path: '../projects/lib/src/theming/fonts/OpenSans/';

@import '../projects/lib/src/theming/reset.scss';
@import '../projects/lib/src/theming/main.scss';

html {
  font-family: $font-name;
  font-size: $font-size--small;
}

The solution proposed by @kroeder works as long as your using components from an Angular application but for libraries, you cannot add the styles property in the angular.json file

@stale stale bot removed the inactive label Apr 23, 2019
@yashsway
Copy link

Try adding your global.scss File into angular.json

Check your defaultProject (there's a defaultProject property inside the json) and add it to the styles list

"styles": [
              "projects/your-cli-project/src/lib/styles/your-styles.scss"
            ],

I do it that way and it works just fine. Is that an option for you?

I did this exact thing, but it doesn't seem to load this for me when I run storybook

@stale
Copy link

stale bot commented May 31, 2019

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!

@stale stale bot added the inactive label May 31, 2019
@stale
Copy link

stale bot commented Jun 30, 2019

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!

@stale stale bot closed this as completed Jun 30, 2019
@ozanmanav
Copy link

Hi @omaracrystal here is how I did it:
in the .storybook/config.jsfiles, add the import with the correct loaders inlined:

import '!style-loader!css-loader!sass-loader!./scss-loader.scss';

Then add/import all the styles you need in the scss-loader.scss file:

$font-path: '../projects/lib/src/theming/fonts/OpenSans/';

@import '../projects/lib/src/theming/reset.scss';
@import '../projects/lib/src/theming/main.scss';

html {
  font-family: $font-name;
  font-size: $font-size--small;
}

The solution proposed by @kroeder works as long as your using components from an Angular application but for libraries, you cannot add the styles property in the angular.json file

Is that working for everyone ? Not working my side :(

@orlov-vo
Copy link

orlov-vo commented Jan 18, 2020

@ozanmanav did you try import it in .storybook/config.js?

PS: because for me it works but I import just .css file without webpack-loaders

@garrettmaring
Copy link

This seems to no longer work using the main.js file structure of Storybook v5.3

@shilman
Copy link
Member

shilman commented Feb 8, 2020

@garrettmaring did you try with .storybook/preview.js rather than .storybook/config.js?

@ycadaner-merkos302
Copy link

@garrettmaring
I finally got it working for .css files using import '!style-loader!css-loader!./main.css'.
At first I tried toying with the webpack config, but I removed all my custom rules, and inlined it like above. Obviously npm install the loaders.

@garrettmaring
Copy link

@shilman yes, that did it 👍 Pretty clear once I saw some documentation on it. There might be some room for clearer docs in the main Storybook documentation. I found this article to be clear.

@shilman
Copy link
Member

shilman commented Feb 11, 2020

@garrettmaring Mind submitting a PR to help improve the docs?

@impurity-dev
Copy link

impurity-dev commented Mar 6, 2020

@garrettmaring
I finally got it working for .css files using import '!style-loader!css-loader!./main.css'.
At first I tried toying with the webpack config, but I removed all my custom rules, and inlined it like above. Obviously npm install the loaders.

Just some FYI that i just figured out, this approach works wonders when serving storybook locally, but it does not work (from what I saw) with build-storybook.

My solution
Add <link rel="stylesheet" href="./your-global-styles.css" /> to the preview-head.html. Then use the -s flag on your-global-styles.css's directory copy the styles to the build directory of storybook. Now the iframe.html "should" be referencing your-global-styles.css from the same directory.

Only issue with this is when running locally, the browser console will say it cannot find localhost/your-global-styles.css but it still works as intended.

If anyone has a better way of approaching this, or knows of a proper solution, let me know :)

@blemaire
Copy link

we serve scss files in storybook using the following:

import '!style-loader!css-loader!sass-loader!./main.scss';

This works fine for us

@lopis
Copy link

lopis commented Mar 16, 2020

@blemaire Where are you using that line?

lallaheeee added a commit to TeamCrazyPerformance/tcp-web that referenced this issue Mar 23, 2020
@4ndv
Copy link

4ndv commented Mar 24, 2020

@blemaire Where are you using that line?

@lopis just create preview.js in the .storybook folder and put that line into it

@llmartinll
Copy link

llmartinll commented Mar 26, 2020

Thanks everyone. Confirming that

  • adding the scss file to .storybook (or whatever place you wish to put it).
  • Creating .storybook/preview.js
  • adding import '!style-loader!css-loader!sass-loader!./styles.scss'; to the preview.js dir
  • adding "css-loader" as a devDependency to package.json

works for us; storybook i.c.w. an Angular 9 library (so no option to add it to the angular.json file)

@vdanchenkov
Copy link

vdanchenkov commented May 8, 2020

In nextjs based setup simple line of import "../styles/main.css"; (as in main app) to .storybook/preview.js adds styles correctly.

@thomasdavis
Copy link

thomasdavis commented May 13, 2020

The above solutions works if all your pathing is relative ../../src/main.scss but my current project uses SCSS global/alias.

My main.js webpack config for Storybook can compile the alias. But when I try import global/alias SCSS into my preview.js then it can't resolve the paths.

Not sure where to go.

@caseytrombley
Copy link

import '!style-loader!css-loader!sass-loader!./scss-loader.scss';

I tried this, but getting error. I need Storybook to know about my global css variables and mixins.

ERR! import '!style-loader!css-loader!sass-loader!./scss-loader.scss';
ERR!        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ERR! 
ERR! SyntaxError: Unexpected string

@caseytrombley
Copy link

In nextjs based setup simple line of import "../styles/main.css"; (as in main app) to .storybook/preview.js adds styles correctly.

Does this styles/main.css contain your global SCSS variables? Do they get applied in Storybook at all? I tried this, but still get SassError: Undefined variable: $my-variable-here

ginpei added a commit to ginpei/tw2021 that referenced this issue Jul 14, 2021
@Jordaneisenburger
Copy link

I can confirm that in the latest version 6.3 "simply" importing a css files in preview.js does not work.

@shilman
Copy link
Member

shilman commented Aug 7, 2021

@Jordaneisenburger Do you a have a reproduction repo you can share? If not, can you create one? See how to create a repro.

@literalpie
Copy link
Contributor

I had a problem today with styles silently failing to load with storybook 6.3 and Angular 12.2. Downgrading Angular to 12.1 fixed the issue for me.

@daeteck
Copy link

daeteck commented Aug 10, 2021

As @literalpie mentioned the global import of a SCSS file stooped working in Storybook 6.3.x with the version 12.2.x of Angular.

@KrisHaney
Copy link

I made a minimal reproduction and hosted on Chromatic. Steps taken to produce are in the readme.md file of the repo.

https://www.chromatic.com/test?appId=6116d0fb97cb10003ce69c94&id=6116da16f8042f003aec800f

https://github.com/KrisHaney/sb6.3-ng12.2

@nharrisanalyst
Copy link

It's works for me, to solve problem with common scss variables, functions.
Tested with nuxt, with using @nuxtjs/style-resources module

  webpackFinal(config, { configType }) {
    config.module.rules.push({
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader', {
        loader: require.resolve('sass-resources-loader'),
        options: {
          // core.scss contains variables, functions, mixins..
          resources: path.resolve(__dirname, '../assets/styles/core.scss')
        }
      }],
      include: path.resolve(__dirname, '../'),
    })

    return config
  }

This Works !!!!

@tschaffter
Copy link

The issue is tracked in #15855

@fosterdouglas
Copy link

Adding my hat in the ring here.

Using Vue 3.2.0 and Storybook 6.3.6, with Bootstrap 5.1, and struggling to get SCSS files working fully.

Attempted:

  • Most of the main.js webpackFinal configurations in the thread above
  • Using @storybook/preset-scss and sassLoaderOptions > additionalData there (this works... ish, but not fully)
  • Importing directly in preview.js, trying both import or require()
  • Using older versions of sass-loader (was using 10.1.1 for a while based on some other thread).. someone had mentioned that sass-loader version needs to match Storybook's precisely, although I'm not sure how to know what that'd be
  • Trying sass-resource-loader, though admittedly I don't fully understand it

Definitely at a loss here, very excited to see some solutions eventually, (or a Vue workaround/thread if anyone has one).

@fosterdouglas
Copy link

In case anyone stumbles on this and needs it, the way I (mostly) solved my particular issue:

The key for my setup was splitting my styles up properly. Making sure that styles I wanted to be injected into every component were added in main.js:

// main.js
...
{
  name: "@storybook/preset-scss",
  options: {
    sassLoaderOptions: {
      additionalData:
        '@import "./src/styles/vars.scss"; @import "./node_modules/bootstrap/scss/_functions.scss"; @import "./node_modules/bootstrap/scss/_variables.scss"; @import "./node_modules/bootstrap/scss/_mixins.scss";',
    },
  },
},
...

And styles/modules that only needed to be loaded once be put in preview.js:

// preview.js
import { app } from "@storybook/vue3";

// import all required bootstrap modules
import "../src/styles/bootstrap.scss";
...

Good luck!

@zaur1003
Copy link

I have just resolved the issue. And you would not believe how easy it is.
Just add
import '../styles/globals.css' to your .storybook/preview.js file

@daeteck
Copy link

daeteck commented Sep 15, 2021

I have just resolved the issue. And you would not believe how easy it is.
Just add
import '../styles/globals.css' to your .storybook/preview.js file

The idea is to use SASS not plain CSS, since it will require a external process in order to convert from SASS to CSS for every change in the global styling file.

As the SASS file is imported and Storybook use Webpack (that basically check all the imports and create a bundle) the conversion from SASS to CSS should be handled by Webpack.

@Charlene-Bx
Copy link

I've following the solution by the great @proxycase with some change for a classic Vue-CLI app:

  // custom webpack configuration
  webpackFinal: async (config, { configType }) => {
    config.module.rules.push({
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', {
        loader: 'sass-loader',
        options: {
          prependData: `@import "@/assets/style/main.scss";`
        }
      }],
      include: path.resolve(__dirname, '../'),
      resolve: {
        alias: {
          "@": path.resolve(__dirname, "../src/"),
          "~": path.resolve(__dirname, "../src/assets/"),
        },
      },
    });
    return config;
  }

Thank you so much @proxycase , you saved my day and more than, i learn so much on this custom webpack build!

@alexandebryakin
Copy link

With this setup, everything works like a charm.

dependencies:

    "@babel/core": "^7.16.12",
    "@storybook/addon-actions": "^6.4.17",
    "@storybook/addon-essentials": "^6.4.17",
    "@storybook/addon-links": "^6.4.17",
    "@storybook/builder-webpack5": "^6.4.17",
    "@storybook/manager-webpack5": "^6.4.17",
    "@storybook/preset-scss": "^1.0.3",
    "@storybook/react": "^6.4.17",
    "@types/node": "^12.20.2",
    "@types/react": "^17.0.38",
    "@types/react-dom": "^17.0.11",
    "babel-loader": "^8.2.3",
    "css-loader": "^6.5.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "sass": "^1.49.7",
    "sass-loader": "^12.4.0",
    "style-loader": "^3.3.1",
    "typescript": "^4.5.5",
    "webpack": "^5.68.0"

./storybook/main.js:

const path = require('path');

module.exports = {
  stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: ['@storybook/addon-links', '@storybook/addon-essentials', '@storybook/preset-scss'],
  framework: '@storybook/react',
  core: {
    builder: 'webpack5',
  },
};

./storybook/preview.js:

import '../assets/stylesheets/_groupstrap.scss'; // <- this is a root stylesheet import

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
};

Also, rather than trying to perform gradual upgrades from storybook v5.*, ..., to v6.* it was easier to remove the ./storybook folder and run the npx sb init --builder webpack5. It automatically looks into the list of dependencies and provides a proper config. For scss better use @storybook/preset-scss.

@Cochonours
Copy link

./storybook/preview.js:

import '../assets/stylesheets/_groupstrap.scss'; // <- this is a root stylesheet import

This works like a charm on a brand new project for storybook

@johnnycopes
Copy link

johnnycopes commented Jun 22, 2022

In my Angular 13 + nx project, I'm setting up Storybook in a specific library and needed to import some third-party CSS for the Storybook app. The example in the docs worked for me:

// project.json

 "build-storybook": {
    "executor": "@nrwl/storybook:build",
    "outputs": ["{options.outputPath}"],
    "options": {
      "uiFramework": "@storybook/angular",
      "outputPath": "dist/storybook/example-lib",
      "config": {
        "configFolder": "libs/example-lib/storybook/.storybook"
      },
      "projectBuildConfig": "example-lib:build-storybook",
      "styles": ["apps/example-app/src/styles.scss"] <-- this line (change to absolute path to your file)
    },
    "configurations": {
      "ci": {
        "quiet": true
      }
    }
  }  

@daniloarcidiacono
Copy link

daniloarcidiacono commented Aug 6, 2022

I had the same problem (Storybook 6.5.9) with SCSS imports not working, while plain CSS imports worked just fine... after quite a bit of debugging, I noticed that the Webpack rule for SCSS files does not have sideEffects set to true, while the CSS rule does (--debug-webpack flag passed to start-storybook):

CSS file rule has sideEffects enabled, while the SCSS one don't

sideEffects basically tells Webpack to not remove "unused" imports (tree-shaking), because they have side effects.

So the fix consists in enabling side effects for the existing SCSS rule (.storybook/main.js file):

const path = require('path');

module.exports = {
    stories: [
        '../src/**/*.stories.mdx',
        '../src/**/*.stories.@(js|jsx|ts|tsx)'
    ],
    addons: [
        '@storybook/addon-links',
        '@storybook/addon-essentials',
        '@storybook/addon-interactions',
        '@storybook/preset-scss'
    ],
    framework: '@storybook/react',
    core: {
        builder: '@storybook/builder-webpack5',
        disableTelemetry: true
    },
    webpackFinal: async (config, { configType }) => {
        // Without this, the SCSS imports on preview.js are removed via tree shaking!
        // By setting sideEffects to true, we disable tree shaking
        // Note that for css files the config already has sideEffects set to true.
        const sassRule = config.module.rules.find(rule => 'test.scss'.match(rule.test));
        sassRule.sideEffects = true;
    
        // Return the altered config
        return config;
    }
};

Hope this helps

@ekowbaah
Copy link

ekowbaah commented Sep 9, 2022

For anyone stuck with this, check out this article:
https://bitsnpixels.dev/blog/import-your-angular-scss-files-in-storybook.html

@ryanoglesby08
Copy link

@daniloarcidiacono Thank you for debugging that! I was struggling with the same issue and your comment helped me resolve it.

I did a little more digging into @storybook/preset-scss and discovered an easier way to set sideEffects: true. You can simply pass it as an option to the addon.

See source here: https://github.com/storybookjs/presets/blob/master/packages/preset-scss/index.js#L31

// .storybook/main.js

module.exports = {
  addons: [
    {
      name: "@storybook/preset-scss",
      options: {
        rule: {
          sideEffects: true,
        },
      }
    }
  ]
}

@SirSerje
Copy link

SirSerje commented Oct 5, 2022

Hi @omaracrystal here is how I did it: in the .storybook/config.jsfiles, add the import with the correct loaders inlined:

import '!style-loader!css-loader!sass-loader!./scss-loader.scss';

Then add/import all the styles you need in the scss-loader.scss file:

$font-path: '../projects/lib/src/theming/fonts/OpenSans/';

@import '../projects/lib/src/theming/reset.scss';
@import '../projects/lib/src/theming/main.scss';

html {
  font-family: $font-name;
  font-size: $font-size--small;
}

The solution proposed by @kroeder works as long as your using components from an Angular application but for libraries, you cannot add the styles property in the angular.json file

JFYI:
.storybook/preview.js:
import '!style-loader!css-loader!sass-loader!./style-loader.scss';

works well 💛

"nx": "14.5.7",
"@angular/core": "~14.1.1",
"storybook": "^6.5.10",
"@nrwl/cli": "14.5.7",

@fireflysemantics
Copy link

If I understand correctly we can import global SCSS styles via .storybook/preview.js now?

I tried this in an Angular 15.2 project and got the following error:

ModuleParseError: Module parse failed: Unexpected token (1:0)
File was processed with these loaders:
 * ./node_modules/resolve-url-loader/index.js
 * ./node_modules/sass-loader/dist/cjs.js
You may need an additional loader to handle the result of these loaders.
> .mat-ripple {
|   overflow: hidden;
|   position: relative;
    at handleParseError (/Users/oleersoy/Temp/storybook2-demo/node_modules/webpack/lib/NormalModule.js:976:19)
    at /Users/oleersoy/Temp/storybook2-demo/node_modules/webpack/lib/NormalModule.js:1095:5
    at processResult (/Users/oleersoy/Temp/storybook2-demo/node_modules/webpack/lib/NormalModule.js:800:11)
    at /Users/oleersoy/Temp/storybook2-demo/node_modules/webpack/lib/NormalModule.js:860:5
    at /Users/oleersoy/Temp/storybook2-demo/node_modules/loader-runner/lib/LoaderRunner.js:407:3
    at iterateNormalLoaders (/Users/oleersoy/Temp/storybook2-demo/node_modules/loader-runner/lib/LoaderRunner.js:233:10)
    at iterateNormalLoaders (/Users/oleersoy/Temp/storybook2-demo/node_modules/loader-runner/lib/LoaderRunner.js:240:10)
    at /Users/oleersoy/Temp/storybook2-demo/node_modules/loader-runner/lib/LoaderRunner.js:255:3
    at context.callback (/Users/oleersoy/Temp/storybook2-demo/node_modules/loader-runner/lib/LoaderRunner.js:124:13)
    at onSuccess (/Users/oleersoy/Temp/storybook2-demo/node_modules/resolve-url-loader/index.js:231:9)

WARN Broken build, fix the error above.
WARN You may need to refresh the browser.

This is what the preview.js looks like:

import { setCompodocJson } from "@storybook/addon-docs/angular";
import docJson from "../documentation.json";
import '../src/styles.scss';

setCompodocJson(docJson);

export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
  docs: { inlineStories: true },
}

Thoughts?

@fireflysemantics
Copy link

OK For Angular 15.2 the following works:

import '!style-loader!css-loader!sass-loader!../src/styles.scss';

@naveedausaf
Copy link

naveedausaf commented Aug 21, 2023

I have just resolved the issue. And you would not believe how easy it is. Just add import '../styles/globals.css' to your .storybook/preview.js file

Tremendous @zaur1003 ! Also works with global scss files in Next.js 13 with Storybook v7.x.

My src/styles/globals.scss is as follows:

@import "resets.scss";

:root {
    --gradient-start: #672280;
    --gradient-end: #A626D3;
}

Note it is importing another (global) scss file from within the same folder, src/styles/resets/scss which contains my css resets. The @import statement specific to CSS/SCSS files, import won't work here and next build would fail

In the code generated by create-next-app scaffolder, this global.scss is imported into src/pages/_app.tsx which is the App component. From there it is available to every component in the app. next build works fine with globals.scss being defined the way it is.

A CSS module src/components/header.module.scss which uses CSS variables defined in globals.scss is as follows.

.outercontainer {
    background: linear-gradient(90deg, var(--gradient-start) 0%, var(--gradient-end) 100%);
    padding: 1.19em 2.31em 1.24em 1.25em;
    display: flex;
    flex-direction: row;
    align-items: center;
}

I put global.scss import into .storybook/preview.ts (as @zaur1003 showed for css):

import "../src/styles/globals.scss";

and voila, CSS definitions in the global scss file (but not SCSS features like mixins; for that you will need to @import ../styles/globals.scss` directly in your SCSS modules where you use them) is available in SCSS modules that are imported in components rendered in iframes in storybook.

My header.tsx component, which imports CSS module header.module.scss, renders correctly based on variables defined in globals.scss (they define two shades of purple for a linear gradient):

image

@pratapraman
Copy link

Here is the solution which works for me
https://storybook.js.org/recipes/sass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests