Storybook: ๋ชจ๋“  Storybook iframe์— ์ „์—ญ ์Šคํƒ€์ผ (scss)์„ ํ•œ ๋ฒˆ ํฌํ•จํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒํ•ฉ๋‹ˆ๊นŒ?

์— ๋งŒ๋“  2019๋…„ 04์›” 01์ผ  ยท  39์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: storybookjs/storybook

๋ฒ„๊ทธ ์„ค๋ช…
๋ชจ๋“  Storybook Iframe์— ๋Œ€ํ•ด ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ (scss)์„ ํ•œ ๋ฒˆ ํ†ตํ•ฉํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ๋ฐฉ๋ฒ•์ด์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์žฌํ˜„ํ•˜๋ ค๋ฉด
์‹œ๋„ :


    • ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด์—์„œ ์ „์—ญ ์Šคํƒ€์ผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    • ๊ฒฐ๊ณผ : ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์ง€๋งŒ ์—ฌ๋Ÿฌ global.scss ์Šคํƒ€์ผ์ด {story #} x ๋ฒˆ ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.

    • ์‚ฌ์šฉ์ž ์ •์˜ ์›นํŒฉ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์ง€์นจ์„ ๋”ฐ๋ฅด์‹ญ์‹œ์˜ค : https://storybook.js.org/docs/configurations/custom-webpack-config/
    • ๊ฒฐ๊ณผ : ์ด๊ฒƒ์€ ์Šคํ† ๋ฆฌ ๋ถ์—๊ฒŒ scss๋ฅผ ์ฝ๋„๋ก ์ง€์‹œ ํ•  ๋ฟ์ด๋ฉฐ ์‹ค์ œ๋กœ ๋ชจ๋“  ์Šคํ† ๋ฆฌ์— ์ ์šฉ๋˜๋Š” ์ „์—ญ ํŒŒ์ผ์„ ์„ค์ •ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.
    • ํ•œ ๊ณณ์—์„œ๋Š” Storybook ์šฉ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๋Ÿฐ ์‹์œผ๋กœ "๊ธ€๋กœ๋ฒŒ"CSS๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
    • ๊ฒฐ๊ณผ : ๋‚ด๊ฐ€ํ•˜๋ ค๋Š” ์ž‘์—… (์—ฌ๋Ÿฌ ์Šคํƒ€์ผ, ๋ฏน์Šค ์ธ, ๋ณ€์ˆ˜ ๋“ฑ)์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ž‘์€ CSS ๋ณ€๊ฒฝ์—๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.
    • .storybook ์•„๋ž˜์˜ ๊ตฌ์„ฑ์—์„œ require ( '../ libs / storybook / global-styles.scss'); loadStories ํ•จ์ˆ˜ ๋‚ด
    • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„
    • Storybook index.ts ๋‚ด์—์„œ ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.
    • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„
    • angular.json ํŒŒ์ผ์„ ํ†ตํ•ด ์ „์—ญ ์Šคํƒ€์ผ ์ถ”๊ฐ€ ์‹œ๋„

      • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™
๋ชจ๋“  ์Šคํ† ๋ฆฌ์˜ Iframe์— ์ ์šฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธ€๋กœ๋ฒŒ (scss) ํŒŒ์ผ์„ ํ•œ ๊ณณ์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ๊ตฌ์„ฑ ์„ค์ •์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ฒด๊ณ„:

  • ์šด์˜์ฒด์ œ : MacOS
  • ๊ธฐ๊ธฐ : Macbook Pro 2015
  • ๋ธŒ๋ผ์šฐ์ € : ํฌ๋กฌ
  • ํ”„๋ ˆ์ž„ ์›Œํฌ : ๊ฐ๋„
  • ์• ๋“œ์˜จ :-[addon-centered, addon-viewport, addon-info]
  • ๋ฒ„์ „ : [^ 5.0.1]

์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ
์ด ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ๋Š” ์Šคํ† ๋ฆฌ ๋ถ์˜ ์ผ๋ถ€ ๊ตฌ์„ฑ์ด ๋ˆ„๋ฝ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

angular has workaround inactive question / support

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="13">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="14">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋“  39 ๋Œ“๊ธ€

global.scss ํŒŒ์ผ์„ angular.json ์ถ”๊ฐ€ํ•ด๋ณด์‹ญ์‹œ์˜ค.

defaultProject (json ๋‚ด๋ถ€์— defaultProject ์†์„ฑ์ด ์žˆ์Œ)๋ฅผ ํ™•์ธํ•˜๊ณ  ์Šคํƒ€์ผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

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

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒํ•˜๊ณ  ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๋‹น์‹ ์„์œ„ํ•œ ์„ ํƒ์ธ๊ฐ€์š”?

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„! ์ตœ๊ทผ์ด ๋ฌธ์ œ์—์„œ ๋งŽ์€ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ์งˆ๋ฌธ, ์˜๊ฒฌ ๋˜๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด ํ† ๋ก ์„ ๊ณ„์†ํ•˜์‹ญ์‹œ์˜ค. ์•ˆํƒ€๊น๊ฒŒ๋„ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃฐ ์‹œ๊ฐ„์ด ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ๊ธฐ์—ฌ์— ์—ด๋ ค ์žˆ์œผ๋ฏ€๋กœ ๋„์›€์ด ํ•„์š”ํ•˜๋ฉด ํ’€ ์š”์ฒญ์„ ๋ณด๋‚ด์ฃผ์‹ญ์‹œ์˜ค. ๋น„ํ™œ์„ฑ ๋ฌธ์ œ๋Š” 30 ์ผ ํ›„์— ๋งˆ๊ฐ๋ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ!

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="13">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="14">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

global.scss ํŒŒ์ผ์„ angular.json ์ถ”๊ฐ€ํ•ด๋ณด์‹ญ์‹œ์˜ค.

defaultProject (json ๋‚ด๋ถ€์— defaultProject ์†์„ฑ์ด ์žˆ์Œ)๋ฅผ ํ™•์ธํ•˜๊ณ  ์Šคํƒ€์ผ ๋ชฉ๋ก์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

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

๋‚˜๋Š” ๊ทธ๋ ‡๊ฒŒํ•˜๊ณ  ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒŒ ๋‹น์‹ ์„์œ„ํ•œ ์„ ํƒ์ธ๊ฐ€์š”?

์ด ์ž‘์—…์„ ์ •ํ™•ํžˆ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ ์Šคํ† ๋ฆฌ ๋ถ์„ ์‹คํ–‰ํ•  ๋•Œ๋กœ๋“œ๋˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„! ์ตœ๊ทผ์ด ๋ฌธ์ œ์—์„œ ๋งŽ์€ ์ผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š์€ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ ์งˆ๋ฌธ, ์˜๊ฒฌ ๋˜๋Š” ๋ฒ„๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด ํ† ๋ก ์„ ๊ณ„์†ํ•˜์‹ญ์‹œ์˜ค. ์•ˆํƒ€๊น๊ฒŒ๋„ ๋ชจ๋“  ๋ฌธ์ œ๋ฅผ ๋‹ค๋ฃฐ ์‹œ๊ฐ„์ด ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ํ•ญ์ƒ ๊ธฐ์—ฌ์— ์—ด๋ ค ์žˆ์œผ๋ฏ€๋กœ ๋„์›€์ด ํ•„์š”ํ•˜๋ฉด ํ’€ ์š”์ฒญ์„ ๋ณด๋‚ด์ฃผ์‹ญ์‹œ์˜ค. ๋น„ํ™œ์„ฑ ๋ฌธ์ œ๋Š” 30 ์ผ ํ›„์— ๋งˆ๊ฐ๋ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ!

์•ˆ๋…•, ๋˜ ๋‚˜์•ผ! ์ด ๋ฌธ์ œ๋ฅผ ๋งˆ๋ฌด๋ฆฌํ•˜์—ฌ ๊ด€๋ฆฌ์ž๊ฐ€ ๋Œ€์‹  ํ˜„์žฌ ๊ฐœ๋ฐœ ๋กœ๋“œ๋งต์— ์ง‘์ค‘ํ•  ์ˆ˜ ์žˆ๋„๋กํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ์–ธ๊ธ‰ ๋œ ๋ฌธ์ œ๊ฐ€ ์—ฌ์ „ํžˆ ์šฐ๋ ค๋˜๋Š” ๊ฒฝ์šฐ ์ƒˆ ํ‹ฐ์ผ“์„ ์—ด๊ณ ์ด ์ด์ „ ํ‹ฐ์ผ“์„ ์–ธ๊ธ‰ํ•˜์‹ญ์‹œ์˜ค. ์Šคํ† ๋ฆฌ ๋ถ์„ ์‚ฌ์šฉํ•ด ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="14">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="15">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ํŽธ์ด ์•„๋‹™๋‹ˆ๋‹ค :(

@ozanmanav .storybook/config.js ์—์„œ ๊ฐ€์ ธ ์˜ค๋ ค๊ณ  ํ–ˆ์Šต๋‹ˆ๊นŒ?

์ถ”์‹  : ์ €์—๊ฒŒ๋Š” ์ž‘๋™ํ•˜์ง€๋งŒ webpack-loaders์—†์ด .css ํŒŒ์ผ ๋งŒ ๊ฐ€์ ธ ์˜ค๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

Storybook v5.3์˜ main.js ํŒŒ์ผ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋” ์ด์ƒ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

@garrettmaring ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์‹œ๋„ ์•Š์•˜๋‹ค .storybook/preview.js ๋ณด๋‹ค๋Š” .storybook/config.js ?

์•ˆ๋…•ํ•˜์„ธ์š”.
๋งˆ์นจ๋‚ด import '!style-loader!css-loader!./main.css' ์‚ฌ์šฉํ•˜์—ฌ .css ํŒŒ์ผ์—์„œ ์ž‘๋™ํ•˜๋„๋กํ–ˆ์Šต๋‹ˆ๋‹ค.
์ฒ˜์Œ์—๋Š” webpack ๊ตฌ์„ฑ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ง€์ • ๊ทœ์น™์„ ์ œ๊ฑฐํ•˜๊ณ  ์œ„์™€ ๊ฐ™์ด ์ธ๋ผ์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ npm์€ ๋กœ๋”๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

@shilman ์˜ˆ, ๊ทธ๋žฌ์Šต๋‹ˆ๋‹ค ๐Ÿ‘ ๋ช‡ ๊ฐ€์ง€ ๋ฌธ์„œ๋ฅผ ๋ณด์•˜์„ ๋•Œ ๊ฝค ๋ถ„๋ช…ํ•ฉ๋‹ˆ๋‹ค. ๋ฉ”์ธ ์Šคํ† ๋ฆฌ ๋ถ ๋ฌธ์„œ์— ๋” ๋ช…ํ™•ํ•œ ๋ฌธ์„œ๋ฅผ์œ„ํ•œ ๊ณต๊ฐ„์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ์‚ฌ ๊ฐ€ ๋ช…ํ™•ํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜์Šต๋‹ˆ๋‹ค.

@garrettmaring ๋ฌธ์„œ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ๋ฐ ๋„์›€์ด๋˜๋„๋ก PR์„ ์ œ์ถœํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

์•ˆ๋…•ํ•˜์„ธ์š”.
๋งˆ์นจ๋‚ด import '!style-loader!css-loader!./main.css' ์‚ฌ์šฉํ•˜์—ฌ .css ํŒŒ์ผ์—์„œ ์ž‘๋™ํ•˜๋„๋กํ–ˆ์Šต๋‹ˆ๋‹ค.
์ฒ˜์Œ์—๋Š” webpack ๊ตฌ์„ฑ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ง€์ • ๊ทœ์น™์„ ์ œ๊ฑฐํ•˜๊ณ  ์œ„์™€ ๊ฐ™์ด ์ธ๋ผ์ธํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ npm์€ ๋กœ๋”๋ฅผ ์„ค์น˜ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด๊ฐ€ ๋ฐฉ๊ธˆ ์•Œ์•„ ๋‚ธ ์ฐธ๊ณ ๋กœ์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ ๋กœ์ปฌ์—์„œ ์Šคํ† ๋ฆฌ ๋ถ์„ ์ œ๊ณต ํ•  ๋•Œ ๊ฒฝ์ด๋กœ์šธ ์ˆ˜ ์žˆ์ง€๋งŒ ๋นŒ๋“œ ์Šคํ† ๋ฆฌ ๋ถ์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค (๋‚ด๊ฐ€ ๋ณธ ๊ฒƒ์—์„œ).

๋‚ด ์†”๋ฃจ์…˜
preview-head.html์— <link rel="stylesheet" href="./your-global-styles.css" /> ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ ๋‹ค์Œ your-global-styles.css ๋””๋ ‰ํ† ๋ฆฌ์˜ -s ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํƒ€์ผ์„ ์Šคํ† ๋ฆฌ ๋ถ์˜ ๋นŒ๋“œ ๋””๋ ‰ํ† ๋ฆฌ์— ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ iframe.html์€ ๋™์ผํ•œ ๋””๋ ‰ํ† ๋ฆฌ์—์„œ your-global-styles.css ๋ฅผ "์ฐธ์กฐํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค".

์ด ๋ฌธ์ œ๋Š” ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•  ๋•Œ๋งŒ ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—์„œ localhost/your-global-styles.css ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๊ณ  ํ‘œ์‹œ๋˜์ง€๋งŒ ์—ฌ์ „ํžˆ ์˜๋„ ํ•œ๋Œ€๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋ˆ„๊ตฌ๋“ ์ง€ ์ด๊ฒƒ์— ์ ‘๊ทผํ•˜๋Š” ๋” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์žˆ๊ฑฐ๋‚˜ ์ ์ ˆํ•œ ํ•ด๊ฒฐ์ฑ…์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค :)

๋‹ค์Œ์„ ์‚ฌ์šฉํ•˜์—ฌ ์Šคํ† ๋ฆฌ ๋ถ์— scss ํŒŒ์ผ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

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

์ด๊ฒƒ์€ ์šฐ๋ฆฌ์—๊ฒŒ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

@blemaire ์–ด๋””์—์„œ ๊ทธ ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@blemaire ์–ด๋””์—์„œ ๊ทธ ๋ผ์ธ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

@lopis ๋Š” .storybook ํด๋”์— preview.js ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ ์ค„์„ ๊ทธ ์•ˆ์— ๋„ฃ์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ํ™•์ธ

  • .storybook (๋˜๋Š” ์›ํ•˜๋Š” ์œ„์น˜)์— scss ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • .storybook/preview.js ๋งŒ๋“œ๋Š” ์ค‘
  • preview.js ๋””๋ ‰ํ† ๋ฆฌ์— import '!style-loader!css-loader!sass-loader!./styles.scss'; ์ถ”๊ฐ€
  • "css-loader" ์— devDependency๋กœ package.json

์šฐ๋ฆฌ๋ฅผ ์œ„ํ•ด ์ผํ•ฉ๋‹ˆ๋‹ค. Storybook icw an Angular 9 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ( angular.json ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๋Š” ์˜ต์…˜ ์—†์Œ)

nextjs ๊ธฐ๋ฐ˜ ์„ค์ •์—์„œ import "../styles/main.css"; (๋ฉ”์ธ ์•ฑ์—์„œ์™€ ๊ฐ™์ด)์˜ ๊ฐ„๋‹จํ•œ ์ค„์€ .storybook/preview.js ์Šคํƒ€์ผ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์†”๋ฃจ์…˜์€ ๋ชจ๋“  ๊ฒฝ๋กœ๊ฐ€ ์ƒ๋Œ€์ ์ธ ../../src/main.scss ์ด์ง€๋งŒ ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์—์„œ SCSS ์ „์—ญ / ๋ณ„์นญ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

Storybook์— ๋Œ€ํ•œ ๋‚ด main.js ์›นํŒฉ ๊ตฌ์„ฑ์ด ๋ณ„์นญ์„ ์ปดํŒŒ์ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ „์—ญ / ๋ณ„์นญ SCSS๋ฅผ ๋‚ด preview.js ๋กœ ๊ฐ€์ ธ ์˜ค๋ ค๊ณ ํ•˜๋ฉด ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์–ด๋””๋กœ ๊ฐ€์•ผํ• ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

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

๋‚˜๋Š” ์ด๊ฒƒ์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์ „์—ญ CSS ๋ณ€์ˆ˜์™€ ๋ฏน์Šค ์ธ์— ๋Œ€ํ•ด ์•Œ๊ธฐ ์œ„ํ•ด Storybook์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

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

nextjs ๊ธฐ๋ฐ˜ ์„ค์ •์—์„œ import "../styles/main.css"; (๋ฉ”์ธ ์•ฑ์—์„œ์™€ ๊ฐ™์ด)์˜ ๊ฐ„๋‹จํ•œ ์ค„์€ .storybook/preview.js ์Šคํƒ€์ผ์„ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

์ด styles / main.css์— ์ „์—ญ SCSS ๋ณ€์ˆ˜๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๊นŒ? ์Šคํ† ๋ฆฌ ๋ถ์— ์ ์šฉ ๋˜๋‚˜์š”? ์‹œ๋„ํ–ˆ์ง€๋งŒ ์—ฌ์ „ํžˆ SassError: Undefined variable: $my-variable-here

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="15">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="16">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ํŽธ์ด ์•„๋‹™๋‹ˆ๋‹ค :(

์•„๋‹ˆ. ๋‚˜๋„ ๋„์›€์ด๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด์ œ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

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

๋ฒ„๊ทธ ์„ค๋ช…
๋ชจ๋“  Storybook Iframe์— ๋Œ€ํ•ด ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ (scss)์„ ํ•œ ๋ฒˆ ํ†ตํ•ฉํ•˜๋Š” ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ช…ํ™•ํ•˜๊ณ  ๊ฐ„๊ฒฐํ•œ ๋ฐฉ๋ฒ•์ด์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์žฌํ˜„ํ•˜๋ ค๋ฉด
์‹œ๋„ :


    • ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ ๋‚ด์—์„œ ์ „์—ญ ์Šคํƒ€์ผ์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

    • ๊ฒฐ๊ณผ : ์Šคํƒ€์ผ์ด ์ ์šฉ๋˜์ง€๋งŒ ์—ฌ๋Ÿฌ global.scss ์Šคํƒ€์ผ์ด {story #} x ๋ฒˆ ๋ฐ˜๋ณต๋ฉ๋‹ˆ๋‹ค.


    • ์‚ฌ์šฉ์ž ์ •์˜ ์›นํŒฉ ๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์ง€์นจ์„ ๋”ฐ๋ฅด์‹ญ์‹œ์˜ค : https://storybook.js.org/docs/configurations/custom-webpack-config/

    • ๊ฒฐ๊ณผ : ์ด๊ฒƒ์€ ์Šคํ† ๋ฆฌ ๋ถ์—๊ฒŒ scss๋ฅผ ์ฝ๋„๋ก ์ง€์‹œ ํ•  ๋ฟ์ด๋ฉฐ ์‹ค์ œ๋กœ ๋ชจ๋“  ์Šคํ† ๋ฆฌ์— ์ ์šฉ๋˜๋Š” ์ „์—ญ ํŒŒ์ผ์„ ์„ค์ •ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.


    • ํ•œ ๊ณณ์—์„œ๋Š” Storybook ์šฉ ๋ฐ์ฝ”๋ ˆ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๋Ÿฐ ์‹์œผ๋กœ "๊ธ€๋กœ๋ฒŒ"CSS๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

    • ๊ฒฐ๊ณผ : ๋‚ด๊ฐ€ํ•˜๋ ค๋Š” ์ž‘์—… (์—ฌ๋Ÿฌ ์Šคํƒ€์ผ, ๋ฏน์Šค ์ธ, ๋ณ€์ˆ˜ ๋“ฑ)์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์ž‘์€ CSS ๋ณ€๊ฒฝ์—๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.


    • .storybook ์•„๋ž˜์˜ ๊ตฌ์„ฑ์—์„œ require ( '../ libs / storybook / global-styles.scss'); loadStories ํ•จ์ˆ˜ ๋‚ด

    • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„


    • Storybook index.ts ๋‚ด์—์„œ ๊ธ€๋กœ๋ฒŒ ์Šคํƒ€์ผ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค.

    • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„

    • angular.json ํŒŒ์ผ์„ ํ†ตํ•ด ์ „์—ญ ์Šคํƒ€์ผ ์ถ”๊ฐ€ ์‹œ๋„

      • ๊ฒฐ๊ณผ : ์•„๋ฌด๊ฒƒ๋„

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™
๋ชจ๋“  ์Šคํ† ๋ฆฌ์˜ Iframe์— ์ ์šฉ ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธ€๋กœ๋ฒŒ (scss) ํŒŒ์ผ์„ ํ•œ ๊ณณ์—์„œ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๊ธฐ๋Œ€ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์•Œ์ง€ ๋ชปํ•˜๋Š” ๊ตฌ์„ฑ ์„ค์ •์ด์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์ฒด๊ณ„:

  • ์šด์˜์ฒด์ œ : MacOS
  • ๊ธฐ๊ธฐ : Macbook Pro 2015
  • ๋ธŒ๋ผ์šฐ์ € : ํฌ๋กฌ
  • ํ”„๋ ˆ์ž„ ์›Œํฌ : ๊ฐ๋„
  • ์• ๋“œ์˜จ :-[addon-centered, addon-viewport, addon-info]
  • ๋ฒ„์ „ : [^ 5.0.1]

์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ
์ด ๋ฌธ์ œ๋ฅผ ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜์žˆ๋Š” ์Šคํ† ๋ฆฌ ๋ถ์˜ ์ผ๋ถ€ ๊ตฌ์„ฑ์ด ๋ˆ„๋ฝ๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ ๋œ ์ ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ทธ๋ ‡๋‹ค๋ฉด ํ•ด๊ฒฐ์ฑ…์€ ๋ฌด์—‡ ์ด์—ˆ์Šต๋‹ˆ๊นŒ? ๊ฐ์‚ฌ!

@caseytrombley ํ•ด๊ฒฐ์ฑ…์€ preview.js์— import '!style-loader!css-loader!sass-loader!./styles.scss'; ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Create React App + Storybook์˜ ๊ฒฝ์šฐ config.js ์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•˜์—ฌ Storybook์— CSS ์žฌ์„ค์ •์„ ์ ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.

import '!style-loader!css-loader!../src/reset.css';

๋ˆ„๊ตฌ๋‚˜ postcss-scss์— ๋Œ€ํ•œ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์‚ฌ์šฉ์ž ์ง€์ • ์›นํŒฉ ๊ตฌ์„ฑ์„ ํ†ตํ•ด ์Šคํ† ๋ฆฌ ๋ถ์— SCSS ์ƒ์ˆ˜ ๋ฅผ ๋ธ”๋กœ๊ทธ ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ˜„์žฌ ๊ตฌ์„ฑ ๋ฒ„๊ทธ https://github.com/storybookjs/storybook/issues/11052 ๋ฐ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์œผ๋กœ ์ž‘์„ฑํ•œ ๋ธ”๋กœ๊ทธ๋ฅผ ์„ค๋ช…ํ•˜๋Š” ๊ฒฐํ•จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

main.js ๊ฐ€์žˆ๋Š” ์„ค์น˜์˜ ๊ฒฝ์šฐ (์˜ˆ : CreateReactApp ํ”„๋กœ์ ํŠธ์—์„œ npx -p @storybook/cli sb init ์‹คํ–‰) preview.js ๋ฅผ ํ˜•์ œ๋กœ ์ถ”๊ฐ€ ํ•œ ๋‹ค์Œ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

// .storybook/preview.js
require('!style-loader!css-loader!../src/css/tailwind-utility-classes.css')

์ด๋Ÿฌํ•œ ๋กœ๋” ์ค‘ ํ•˜๋‚˜๊ฐ€ ์„ค์น˜๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ๋ถˆํ‰ํ•˜๋Š” ๊ฒฝ์šฐ (CRA ํ”„๋กœ์ ํŠธ ์ธ ๊ฒฝ์šฐ ํ•ด๋‹น) ์ˆ˜๋™์œผ๋กœ ์„ค์น˜ํ•˜์‹ญ์‹œ์˜ค (์˜ˆ : yarn add style-loader css-loader ).

upvoted / deprecated ์†”๋ฃจ์…˜์ด ์‹คํŒจ ํ•  ๋•Œ ์‚ฌ๋žŒ๋“ค์ด ์†”๋ฃจ์…˜์„ ์œ„ํ•ด ๋งจ ์•„๋ž˜๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ๋„๋ก ์Šค๋ ˆ๋“œ๋ฅผ ์ž ๊ทธ์‹ญ๋‹ˆ๊นŒ?

@garrettmaring ๋‹น์‹ ๊ณผ ํ•จ๊ป˜ ์‹œ๋„ ์•Š์•˜๋‹ค .storybook/preview.js ๋ณด๋‹ค๋Š” .storybook/config.js ?

๋‚ด๊ฐ€ ๋งŒ๋“ค ๋•Œ styles.css ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์—์„œ ํŒŒ์ผ์„ํ•˜๊ณ  ๊ทธ๊ฒƒ์„ ๊ฐ€์ ธ import './styles.css'; ๋‚ด ์•ˆ์— preview.js ํŒŒ์ผ, ๋‚ด ๋™ํ™”๊ฐ€ ๊ฐ‘์ž๊ธฐ ๋‹จ์ง€๋กœ๋“œ ์ƒํƒœ์— ๋ถ™์–ด์ž…๋‹ˆ๋‹ค ... :(

๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•„์‹ญ๋‹ˆ๊นŒ?

์›น ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•œ open-wc ๊ตฌ์„ฑ ๊ณผ ํ•จ๊ป˜ ์Šคํ† ๋ฆฌ ๋ถ์„ ์‚ฌ์šฉํ•˜๊ณ  preview.js ๋ฐ main.js ํŒŒ์ผ์ด .storybook ํด๋”์— ์žˆ์Šต๋‹ˆ๋‹ค.

@dcts ๋Š” ./styles.css ๊ฐ€ Tailwind ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ฐธ์กฐํ•˜๊ฑฐ๋‚˜, ์‚ฌ์ „ ์ฒ˜๋ฆฌํ•ด์•ผํ•˜๋Š” ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋…๋ฆฝ ์‹คํ–‰ ํ˜• ํŒŒ์ผ๋กœ "ํŒŒ์†"๋˜๊ธฐ ๋•Œ๋ฌธ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„ธ ๊ฐ€์ง€๋ฅผํ•ด์•ผํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. ์ž…๋ ฅ CSS ํŒŒ์ผ์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ €์—๊ฒŒ๋Š” Tailwind ์„ค์ •์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์„ ๊ฐ€์ ธ ์˜ค๋Š” css/tailwind.css ์ž…๋‹ˆ๋‹ค.
  2. ์Šคํ† ๋ฆฌ ๋ถ์„ ์‹คํ–‰ํ•  ๋•Œ ๋จผ์ € ํ•ด๋‹น ํŒŒ์ผ์„ ๋นŒ๋“œํ•˜์‹ญ์‹œ์˜ค. ์ €์—๊ฒŒ ์ด๊ฒƒ์€ PostCSS ๋ช…๋ น์ด์—ˆ์Šต๋‹ˆ๋‹ค postcss css/tailwind.css -o css/index.css
  3. .storybook/preview.js (ํ•„์š”ํ•œ ๊ฒฝ์šฐ ํ•ด๋‹น ํŒŒ์ผ ์ƒ์„ฑ)์— import '../css/index.css

Twin ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ ์˜ˆ์ƒ๋Œ€๋กœ์ด ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import tw, { styled } from 'twin.macro'

const StyledReactionButton = styled.button`
  ${tw`bg-blue-400 bg-opacity-25`}
`

๋” ๋‚˜์€ ํ•ด๊ฒฐ์ฑ…์€ postcss ๋‹จ๊ณ„๋ฅผ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์Šคํ† ๋ฆฌ ๋ถ ์›นํŒฉ ๊ตฌ์„ฑ์„ ํŽธ์ง‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

scss์™€ ํ•จ๊ป˜ Vue.js๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚ด ๋ฌธ์ œ๋Š” preview.js์—์„œ ์ „์—ญ scs๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋‚ด ํฌ๋กฌ devtolls๊ฐ€ ๋งค์šฐ ๋Š๋ฆฌ๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€์žˆ๋Š” ์‚ฌ๋žŒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๋Œ€์•ˆ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ๊ฐ ์Šคํ† ๋ฆฌ์—์„œ ๊ธ€๋กœ๋ฒŒ scs๋ฅผ ๊ฐ€์ ธ ์˜ค์ง€ ์•Š์œผ๋ ค ๊ณ ํ•ฉ๋‹ˆ๋‹ค.

์œ„์˜ ์†”๋ฃจ์…˜์€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ–ˆ์ง€๋งŒ __from official docs__ ์ด ๋ฐฉ๋ฒ• ์€ ์ „์ฒด ํ”„๋กœ์ ํŠธ์—์„œ ๋ฌธ์ œ๋ฅผ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•ด, scss ๋กœ๋”๋ฅผ ์„ค์ •ํ•˜๋ ค๋ฉด Webpack ๊ตฌ์„ฑ์„ ํ™•์žฅํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค.

๊ณต์‹ ๋ฌธ์„œ์˜ ์ƒ˜ํ”Œ ์ฝ”๋“œ

// .storybook/main.js

const path = require('path');

// Export a function. Accept the base config as the only param.
module.exports = {
  webpackFinal: async (config, { configType }) => {
    // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    // Make whatever fine-grained changes you need
    config.module.rules.push({
      test: /\.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'],
      include: path.resolve(__dirname, '../'),
    });

    // Return the altered config
    return config;
  },
};

์šฉ๋ฒ•

์ด์ œ .storybook/preview.js ์—์„œ scss ํŒŒ์ผ์„ ์–ด์›จ์ด๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// .storybook/preview.js

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

// ...

... ๋˜ํ•œ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ๋„ :

<!-- src/components/MyComponent.vue -->

<template>
  ...
</template>

<script>
// ...
</script>

<style lang="scss">
<strong i="18">@import</strong> "../styles/components/components.my-component";
</style>

preview.js ์—์„œ ์ƒ๋‹นํ•œ ๊ทœ๋ชจ์˜ SCSS ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ€์ ธ ์˜ค๋ฉด ํ”„๋กœ์ ํŠธ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์— ๋Œ€ํ•ด 5 ์ดˆ ์ด์ƒ์˜ ์žฌ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์Šคํ† ๋ฆฌ๋กœ ์˜ฎ๊ธฐ๋ฉด ๋ชจ๋“  ๊ฒƒ์ด <1 ์ดˆ์˜ ์žฌ ์ปดํŒŒ์ผ ์‹œ๊ฐ„์œผ๋กœ ๋˜๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค ..

Gatsby ๋ฐ ํ‘œ์ค€ scss ์‚ฌ์ „ ์„ค์ • ๊ณผ ํ•จ๊ป˜ Storybook์„ ์‚ฌ์šฉํ•˜๊ณ  global.scss ํŒŒ์ผ์„ preview.js ๊ฐ€์ ธ์˜จ ํ›„ ์Šคํƒ€์ผ์ด ์„ ํƒ๋˜์ง€๋งŒ global.scss ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ ์ด๋ฅผ ๊ตฌ์„ฑ ์š”์†Œ์—์„œ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

ERROR in ./src/stories/button.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/stories/button.scss)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Undefined variable: "$black".

global.scss ํŒŒ์ผ์ด ๋„ˆ๋ฌด ๋Šฆ๊ฒŒ๋กœ๋“œ๋˜๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ตฌ์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. preview.js ์ „์—ญ ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ๋ฒ•์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฒ„๊ทธ ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ตœ์‹  ์ •๋ณด

๋ช…๋ น์ด ์•„๋‹™๋‹ˆ๋‹ค. global.scss์— ๋‹ค์Œ์„ ์ž‘์„ฑํ•˜๋ฉด.

body {
    background-color: black;
}

Button.scss์— ๋‹ค์Œ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

body {
  background-color:green;
}

๋ฐฐ๊ฒฝ์ƒ‰์€ ์‚ฌ์‹ค ๋…น์ƒ‰์ž…๋‹ˆ๋‹ค. ์ด๋Š” Buttons.scss๊ฐ€ Global.scss ํ›„์—๋กœ๋“œ๋˜์ง€๋งŒ ๋ณ€์ˆ˜๋Š” ์—ฌ์ „ํžˆ ์„ ํƒ๋˜์ง€ ์•Š์Œ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๊ฒฐ์ฑ…
์ด์ฆˆ, ์˜ค๋Š˜ ๋งŽ์ด ๋ฐฐ์› ์–ด์š”. ์ฃผ๋œ ๋ฌธ์ œ๋Š” sass ๋ณ€์ˆ˜๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ ์–ธ ๋œ ํŒŒ์ผ์—์„œ๋งŒ ์ •์˜๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ๊ฐ„์— ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด sass-modules๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ•ฉ๋‹ˆ๋‹ค. ์ด์ „ ๋ฐฉ๋ฒ•์€ @import ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์—ˆ์ง€๋งŒ ์ƒˆ๋กœ์šด ์„ ํ˜ธ๋˜๋Š” ๋ฐฉ๋ฒ•์€ @use์ž…๋‹ˆ๋‹ค. @use pathtomodule/global.scss button.scss ์™€ ๊ฐ™์€ ๋ชจ๋“  ๋ชจ๋“ˆ์„ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค. ์ œ ๊ฒฝ์šฐ์—๋Š” preview.js ์˜ ๊ฐ€์ ธ ์˜ค๊ธฐ๊ฐ€ ์ค‘๋ณต๋ฉ๋‹ˆ๋‹ค.

๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๊ฐ€์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. @use ๋Š” ํ˜„์žฌ dart sass์—์„œ๋งŒ ์ง€์›๋ฉ๋‹ˆ๋‹ค. node-sass๋ฅผ ์„ค์น˜ํ–ˆ์Šต๋‹ˆ๋‹ค ( npm i node-sass --save-dev ). dart-sass ( npm i dart-sass --save-dev )๋ผ๋Š” ํŒจํ‚ค์ง€๊ฐ€ ์žˆ์ง€๋งŒ ์ด์ „์— ์–ธ๊ธ‰ ํ•œ ์‚ฌ์ „ ์„ค์ •์— ๋งž๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. Dart sass๋Š” ์ผ๋ฐ˜ sass๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค . npm i sass --save-dev ๊ฐ„๋‹จํžˆ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @Piepongwong ,

๋‚˜๋Š” Gatsby๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ Vue์—์„œ ๋ชจ๋“  mixin ๋ฐ ๋ณ€์ˆ˜ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ _common.scss ๋ผ๋Š” ํ•˜๋‚˜์˜ ํŒŒ์ผ์— ๋„ฃ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

<style lang="scss">
<strong i="9">@import</strong> 'path/to/styles/_common.scss';
<strong i="10">@import</strong> 'path/to/styles/components/_components.component.scss';
</style>

์ด๋Ÿฐ ์‹์œผ๋กœ ๋‚˜๋Š” ํ•ญ์ƒ ๋‚ด ๋ฏน์Šค ์ธ๊ณผ ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ํ™•์‹ ํ•˜์ง€๋งŒ ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ์™€ ๋ณ€์ˆ˜๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ถ”์ƒํ™”ํ•ด์•ผํ•œ๋‹ค๋Š” ์ ์„ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ชจ๋ฒ” ์‚ฌ๋ก€๋ฅผ ๋ณด๋ ค๋ฉด inuitcss ๋ฅผ ์ฐธ์กฐํ•˜์‹ญ์‹œ์˜ค.

๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="15">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="16">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ํŽธ์ด ์•„๋‹™๋‹ˆ๋‹ค :(

๋‚˜๋ฅผ ์œ„ํ•ด :( ๋‚˜๋Š” next.js ๋ฐ reactstrap์œผ๋กœ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋‚ด ์Šคํƒ€์ผ ํด๋”์—์„œ app.scss๋ฅผ๋กœ๋“œํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค : /

์•ˆ๋…•ํ•˜์„ธ์š” @omaracrystal ์€ ์ œ๊ฐ€ ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
.storybook/config.js ํŒŒ์ผ์—์„œ ์˜ฌ๋ฐ”๋ฅธ ๋กœ๋”๋ฅผ ์ธ๋ผ์ธ์œผ๋กœ ๊ฐ€์ ธ ์˜ค๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜์‹ญ์‹œ์˜ค.

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

๊ทธ๋Ÿฐ ๋‹ค์Œ scss-loader.scss ํŒŒ์ผ์—์„œ ํ•„์š”ํ•œ ๋ชจ๋“  ์Šคํƒ€์ผ์„ ์ถ”๊ฐ€ / ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

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

<strong i="16">@import</strong> '../projects/lib/src/theming/reset.scss';
<strong i="17">@import</strong> '../projects/lib/src/theming/main.scss';

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

@kroeder ๊ฐ€ ์ œ์•ˆํ•œ ์†”๋ฃจ์…˜์€ Angular ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ•œ ์ž‘๋™ํ•˜์ง€๋งŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๊ฒฝ์šฐ angular.json ํŒŒ์ผ์— styles ์†์„ฑ์„ ์ถ”๊ฐ€ ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

๋ชจ๋‘์—๊ฒŒ ํšจ๊ณผ๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚ด ํŽธ์ด ์•„๋‹™๋‹ˆ๋‹ค :(

๋‚˜๋ฅผ ์œ„ํ•ด :( ๋‚˜๋Š” next.js ๋ฐ reactstrap์œผ๋กœ ์‹œ๋„ํ–ˆ์ง€๋งŒ ๋‚ด ์Šคํƒ€์ผ ํด๋”์—์„œ app.scss๋ฅผ๋กœ๋“œํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค : /

@hayatbiralem ๋ฐฉ์‹์œผ๋กœ ์‹œ๋„ํ•˜์‹ญ์‹œ์˜ค-์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ตœ์‹  ๋ฒ„์ „์˜ ๋™ํ™”์ฑ… @storybook/[email protected] ์—์„œ ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€์—๊ฒŒ ๋„์›€์ด๋˜๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

// .storybook/main.js
const path = require('path');

module.exports = {
  "stories": [
    "../stories/**/*.stories.mdx",
    "../stories/**/*.stories.@(js|jsx|ts|tsx)",
    "../app/frontend/components/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    '@storybook/preset-scss'
  ],
  webpackFinal: async (config) => {
    // this sets the default path for modules
    config.resolve.modules = [
      ...(config.resolve.modules || []),
      path.resolve(__dirname, "../app/frontend"),
    ];

    config.module.rules.map(rule => {
      if (rule.test instanceof RegExp && rule.test.toString() === '/\\.s[ca]ss$/') {
        rule.use.push({
          loader: require.resolve('sass-resources-loader'),
          options: {
            resources: [
              path.resolve(__dirname, '../app/frontend/styles/base/_variables.scss')
            ]
          }
        })
      }
      return rule
    })
    return config;
  },
}
์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰