티스토리 뷰

728x90
반응형

storybook + ts+ emotion + storybook 설정 -  SassError: SassError: expected "{". 

 

storybook 설정하는데 있어서 엄청 삽질을 해서 기록해 두려한다.

 

--------------

 

설치된 환경 

- 기타 다른 패키지도 많이 설치 되었지만 필수적으로 필요한 것만 나열했다.

@craco/craco ( Create-React-App Configuration Override ) - CRA에 config 설정 덮어쓰기 위한 패키지
craco-alias ( 경로 축약을 위한 즉 alias 설정 ../ 를 @ 같은 것으로~)
craco-sass-resources-loader ( craco 패키지에 scss 파일 로드를 위한 로더 )
@emotion/react
@emotion/styled
@emotion/babel-plugin ( className 에 커스텀 라벨링 ) 
@emotion/babel-preset-css-prop ( /** @jsxImportSource @emotion/react */ 를 매번 로드 안해도 되게끔 해줌 )
typescript 
storybook

 

처음 부터 에러가 났던것은 아니였다. Storybook 에서 전역으로 SCSS 를 지정하려고 했는데 일어난 에러였다.

우선 에러 내용이 SassError: SassError: expected "{".   라고 나오는 것이 일단 먼가 webpack 에서 sass-loader 설정을 별도로 해야 하는 건가?? 라는 물음으로 파보기 시작했다.

 

문제제기한 부분은 stackoverflow 에서 검색해 보니 딱히 해결된 답변은 없는 듯 해보였다.

https://stackoverflow.com/questions/67140412/storybook-react-sasserror-expected

 

Storybook React SassError: expected "{"

Trying to setup a Storybook using .scss file. Following the doc > // .storybook/main.js const path = require('path'); // Export a function. Accept the base config as the only param. module.exp...

stackoverflow.com

 

스토리북 git issue 게시판에서도 깔끔히 해결된 부분은 보이질 않았다.

https://github.com/storybookjs/storybook/issues?q=sassError 

 

GitHub - storybookjs/storybook: 📓 The UI component explorer. Develop, document, & test React, Vue, Angular, Web Components, E

📓 The UI component explorer. Develop, document, & test React, Vue, Angular, Web Components, Ember, Svelte & more! - GitHub - storybookjs/storybook: 📓 The UI component explorer. Develop, doc...

github.com

 

그러나 google 검색 중 아래 URL 을 보고 힌트를 얻었다.

https://dev.to/mdrahiem/add-less-scss-global-styles-in-storybook-1k50

 

Add .less/.scss global styles in storybook

I am trying to integrate storybook tool with my react app. My app is using .less styles and I've a si...

dev.to

대충 내용은 storybook 의 main.js에서 webpack 설정을 좀 손보고 preview.js 에다 전역 scss 파일을 import 시킨다는 것이였다. 결론부터 말하자면 똑같이 진행해 봤으나 안되는 ㅠㅠ  

 

아무튼 코드는 아래와 같은 순서로 진행했다.

mini-css-extract-plugin 플러그인은 필요가 없어서 해당부분은 제거하고 style-loader, css-loader, sass-loader 설치했다.

npm i -D style-loader css-loader sass-loader

main.js 

//const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  ......중략............... ,
  "addons": [
    ......중략...............
    '@storybook/preset-scss'
  ],
  "webpackFinal": async (config, { configType }) => {
    config.module.rules.push({
      // this is for both less and scss
      test: /.*\.(?:c|sa|sc)ss$/,
      loaders: [
        'style-loader',
        'css-loader',
        'sass-loader'
      ]
    });
    /* mini-css-extract-plugin 필요없어서 제거 
     config.plugins.push(new MiniCssExtractPlugin({
      ......중략...............
    }));
    */
    return config;
  },
}

preview.js

import '!style-loader!css-loader!sass-loader!../src/assets/scss/styles.scss';
export const parameters = {
  ..... 중략 ........
}

 

일단 웹팩을 5 버전에 맞는 문법은 아니라서 더 그랬던 거 같다. rules.loaders 는 use 로 대체 되었기 때문에 해당 부분을 바꿔서 해봤다.역시나 한번에 되질 않는 ㅠㅠ

 

에러 내용은 아래와 같았다.

ModuleBuildError: Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
SyntaxError

 

모듈 빌드가 안되는 먼가 Syntax의 문제인 듯 했지만 먼지를 잘 모르겠는.... 근데 가만히 생각해보니 preview.js 에서 import '!style-loader!css-loader!sass-loader!../src/assets/scss/styles.scss';  라고 이미 선언했는데 굳이 webpack 에서 재설정할 필요가 있을까라는 의구심이 들어 main.js 에서 webpackFinal 설정한 부분을 전부 지우고 실행해 봤는데 오오 잘된다!!!!!!  코드는 아래와 같다.

 

main.js

const path = require("path");
// const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
    "stories": [
        "../src/**/*.stories.mdx",
        "../src/**/*.stories.@(js|jsx|ts|tsx)"
    ],
    "addons": [
        "@storybook/addon-links",
        "@storybook/addon-essentials",
        "@storybook/addon-interactions",
        "@storybook/preset-create-react-app",
    ],
    "framework": "@storybook/react",
    "core": {
        "builder": "@storybook/builder-webpack5"
    },
    "webpackFinal":async (config, { configType }) => {
        //storybook 에 알리어스 추가
        config.resolve.alias["@"] = path.resolve(__dirname, "../src/");
        return {
            ...config
        }
    }
}

여기까지 대충 일단락은 된 셈이다. 이렇게 하면 끝일 거 같은데 또 또 찝찝한 기분이....ㅠㅠ

 

 

-----------------

 

그냥 webpackFinal 설정만으로 끝내버릴 순 없을까 라는 고민 끝에 여러 삽질을 통해 아래 URL 를 보고 참고하여 해결하였다.

즉 storybook 에 있는 main.js 에서 webpackFinal 설정만으로 전역 scss 로드하는 법이다.

https://webpack.kr/loaders/sass-loader/#additionaldata

 

sass-loader | 웹팩

웹팩은 모듈 번들러입니다. 주요 목적은 브라우저에서 사용할 수 있도록 JavaScript 파일을 번들로 묶는 것이지만, 리소스나 애셋을 변환하고 번들링 또는 패키징할 수도 있습니다.

webpack.kr

 

아래는 해결한 코드 부분이다.

preview.js ( 기존에 import 한 부분은 주석처리한다. )

// main.js 에서 설정하기에 아래 import 코드는 제거 
// import '!style-loader!css-loader!sass-loader!../src/assets/scss/styles.scss';
export const parameters = {
  ..... 중략 ........
}

 

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/addon-interactions",
        "@storybook/preset-create-react-app",
    ],
    "framework": "@storybook/react",
    "core": {
        "builder": "@storybook/builder-webpack5"
    },
    "webpackFinal":async (config, { configType }) => {
        // sass-loader 설정추가 - webpackFinal 만으로 전역 scss 추가  
        config.module.rules.push({
            test: /.*\.(?:c|sc|sa)ss$/,
            use: [
               //"style-loader",
               //"css-loader",
                {
                    loader: 'sass-loader',
                    options: {
                        additionalData: `
                                    @import "./src/assets/scss/styles.scss";
                                    `
                    }
                }
            ]
        });
    
        //storybook 에 알리어스 추가
        config.resolve.alias["@"] = path.resolve(__dirname, "../src/");
        return {
            ...config
        }
    }
}

추가로 부연설명하자면  style-loader 와 css-loader 로 인해 문법 문제가 좀 발생해서 그냥 주석처리 해버리고 대신 정규표현식 test 하는 부분에 css, sass, scss 를 체크하게끔 해두고 sass-loader 만 설정하였더니 해결되었다. 

 

 

-----------------------------

 

 

이것 외에도 찾아보니 storybook tutorials 홈페이지에서도 해당 부분에 대한 설명이 있었는데 조금 수정해 보니 잘 되어서 기재해 본다.

https://storybook.js.org/tutorials/design-systems-for-developers/react/ko/build/

 

Storybook Tutorials

Learn how to develop UIs with components and design systems. Our in-depth frontend guides are created by Storybook maintainers and peer-reviewed by the open source community.

storybook.js.org

 

아래는 해당 페이지에서 전역 스타일 추가 부분만 발췌했다.

src/shared/global.js
import { createGlobalStyle, css } from 'styled-components';

import { color, typography } from './styles';

+ export const fontUrl = 'https://fonts.googleapis.com/css?family=Nunito+Sans:400,700,800,900';

export const bodyStyles = css`
  /* Same as before */
`;

export const GlobalStyle = createGlobalStyle`
 body {
   ${bodyStyles}
 }`;

스토리북의 GlobalStyle 컴포넌트를 사용하기 위해 컴포넌트 래퍼(wrapper)인 데코레이터(decorator)를 활용할 수 있습니다. 하나의 앱 안이라면 그 컴포넌트를 앱 레이아웃 최상단에 놓겠지만 스토리북에서는 프리뷰 설정 파일을 사용해서 모든 스토리를 그 컴포넌트 안에 넣고 감싸도록 합니다. .storybook/preview.js

.storybook/preview.js
+ import React from 'react';

+ import { GlobalStyle } from '../src/shared/global';

/*
 * Global decorator to apply the styles to all stories
 * Read more about them at:
 * https://storybook.js.org/docs/react/writing-stories/decorators#global-decorators
 */
+ export const decorators = [
+   Story => (
+     <>
+       <GlobalStyle />
+       <Story />
+     </>
+   ),
+ ];

/*
 * Read more about global parameters at:
 * https://storybook.js.org/docs/react/writing-stories/parameters#global-parameters
 */
export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
};

라고 한다. 

 

 

 

해서 우선 내가 설치한 환경에 맞게 전역 스타일을 선언할 .tsx 를 먼저 추가했다. 

파일이름만 변경했다.

 

src/shared/globalStyle.tsx( 위 소스에선 src/shared/global.js )

import React from 'react';
import { Global, css } from '@emotion/react';
import * as rootStyle from '@/assets/scss/styles.scss';

export const GlobalStyle = ()=>{
    return <Global styles={css`${rootStyle}`}/>;
}

 

.storybook/preview.js( 튜토리얼에 있는  decorators 부분만 추가했다. )

import {GlobalStyle} from '../src/shared/globalStyle';

export const decorators = [
    (Story) => (
        <>
            <GlobalStyle />
            <Story />
        </>
    ),
];

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

 

 

.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/addon-interactions",
        "@storybook/preset-create-react-app",
    ],
    "framework": "@storybook/react",
    "core": {
        "builder": "@storybook/builder-webpack5"
    },
    "webpackFinal":async (config, { configType }) => {
        // sass-loader 설정추가 
        config.module.rules.push({
            test: /.*\.(?:c|sc|sa)ss$/,
            use: ['sass-loader']
        });
    
        //storybook 에 알리어스 추가
        config.resolve.alias["@"] = path.resolve(__dirname, "../src/");
        return {
            ...config
        }
    }
}

main.js 에서 기존에 scss 파일을 로드해 두었었는데 preview.js 에서 로드 되고 있기에 해당 부분은 제거 하였고 sass-loader 를 쓴다고 선언만 시켜놨다. 먼가 좀더 심플한거 같기도 하고 ..... 암튼 튜토리얼페이지에서 제공하는 정보이니 저게 좀 더 신뢰가 가는 듯 하다.

 

 

 

아래 URL 에서 storybook-addon-next 애드온을 설치해서 해결했다고는 하는데 해보지는 않았다. 더 이상 소스를 뒤집고 삽질하기에는 너무 지쳐버림 ㅠㅠ 

https://lightrun.com/answers/storybookjs-storybook-react--storybook--scss-modules-not-working

 

React + Storybook + SCSS modules not working

Lightrun Answers. Where developers land when they google for errors and exceptions

lightrun.com

 

이 정도 선에서 storybook 설정으로 가기 위한 준비는 끝난 것 같다. 이제부터 스토리북에 컴포넌트 추가를 ㅠㅠ 

728x90
반응형
댓글