[Webpack] SCSS to CSS

jhj46456·2020년 9월 7일
2
post-thumbnail

webpack v4 기준입니다.

다음의 개발 환경을 구성합니다.

  • Library : 없음
  • JS : 없음
  • CSS : scss 👉 css 변환

기본 지식

내용을 본격적으로 들어가기 전에 핵심 키워드들을 정리해보겠습니다.

  • css : 여러분이 알고있는 그 CSS 맞습니다.
  • css-loader : 분석된 CSS code와 함께 CSS file을 불러옵니다.
  • postcss : JS로 CSS를 변환하기 위한 tool
  • postcss-loader : postCSS를 사용하여 CSS/SSS file을 변환 (i.e. 호환성 문제 해결)
  • sass : (공식문서 피셜) 세계에서 가장 안정적이고 강력한 CSS 확장 언어
  • sass-loader : SASS/SCSS file들을 불러오고 CSS로 내보냅니다.
  • autoprefixer : postCSS 플러그인, css를 작성하면 옵션에 따라 브라우저 지원 범위를 넓혀준다.

autoprefixer가 무엇인지 한 줄로 누구나 이해할 수 있는 그런 문장을 10분 간 생각해보았으나 떠오르질 않아 코드로 대체합니다.

# 변환 전
.example {
    display: grid;
    transition: all .5s;
    user-select: none;
    background: linear-gradient(to bottom, white, black);
}

# 변환 후
.example {
    display: -ms-grid;
    display: grid;
    -webkit-transition: all .5s;
    -o-transition: all .5s;
    transition: all .5s;
    -webkit-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
            user-select: none;
    background: -webkit-gradient(linear, left top, left bottom, from(white), to(black));
    background: -o-linear-gradient(top, white, black);
    background: linear-gradient(to bottom, white, black);
}

이정도면 기초 지식은 다 습득하신 것 같네요.

webpack 설정

디렉터리 구조

assets
  ㄴ js
     ㄴ main.js
  ㄴ scss
     ㄴ _colors.scss
     ㄴ home.scss
     ㄴ styles.scss
build(empty)
node_modules
  ㄴ ...
package.json
package-lock.json

일단 파일만 만들어둡니다.

아시다시피 webpack의 core concept는 6개로 구성되어 있습니다.

  • Entry
  • Output
  • Loaders
  • Plugins
  • Mode
  • Browser Compatibility

먼저 core package 설치부터 하겠습니다.

npm i webpack webpack-cli -D

https://webpack.js.org/concepts/ 공식 문서를 기반으로 진행하면서 설정하겠습니다.

webpack.config.js를 생성합니다.

touch webpack.config.js

Mode

📌 webpack environment-variables docs
📌 webpack environment-variables option docs

webpack 환경 변수에 따라 development, production, none 세 가지로 설정할 수 있습니다.

기본값production입니다.

📚 webpack.config.js 
         👇   
module.exports = (webpackEnv) => {
  return {
    mode: webpackEnv,
  };
};

script 작업할 때 --env development/production cli 옵션으로 넣어줄 예정입니다.
env 옵션으로 받은 문자열은 webpackEnv로 넘어갑니다.

Entry

번들 작업을 할 파일을 선택합니다.

entry: string | [string]

index.js를 entry에 넣어줍니다.

📚 webpack.config.js 
          👇   
module.exports = (webpackEnv) => {
  return {
    ...
    entry: "./src/index.js",
  };
};

여기서 잠깐!

Q. scss를 css로 바꾸는 건데 js 파일을 작업 영역에 넣는 이유가 있나요?

A. webpack의 entry point는 js로 시작해서 모듈로 묶여진 다른 js / scss를 파악합니다.

Output

번들 결과물이 저장될 경로를 지정합니다.

자주 쓰이는 옵션으로는 pathfilename이 있습니다.

  • path : 디렉터리 위치
  • filename: 결과물 파일명

filename의 value를 [ ]으로 감싸면 entry 파일명 그대로 이름을 만들어줍니다. (i.e. [name].js)

공식 문서 예제에서 path만 수정해봤습니다.

📚 webpack.config.js 
          👇   
module.exports = (webpackEnv) => {
  return {
    ...
    output: {
      path: path.resolve(__dirname, "build", "static"),
      filename: "my-first-webpack.bundle.js",
    },
  };
};

여기서 잠깐!

Q. 출력 옵션에 CSS를 내보내지 않는 이유가 있나요?

A. Plugin으로 CSS만 추출해서 파일로 내보낼 예정입니다.

Loaders

📌 사용 가능한 loaders 목록

webpack은 기본 설정에서 .js와 .json만 이해가 가능합니다.

이 항목에서는 '어떤 확장자는 이렇게 처리해라~'같은 설정을 해줍니다.

옵션은 다음과 같습니다.

  • test : 이 확장자는 webpack이 해석할 것입니다.
  • use : 변환을 위해 사용하는 loader
  • exclude : 제외할 file/directory

sass-loader docs를 보고 필요한 패키지를 설치합니다.

npm i node-sass sass-loader css-loader -D

우리는 scss 확장자를 읽어서 css로 내보내는게 목적이기 때문에 sass-loader docs를 보고 설정해봤습니다.

📚 webpack.config.js
          👇
module.exports = (webpackEnv) => {
  return {
    ...
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: ["css-loader", "sass-loader"],
        },
      ],
    },
  };
};

여기서 잠깐!

Q. sass-loader docs에서는 style-loader를 사용했는데, 넣지 않은 이유가 있나요?

A. style-loader는 설명이 Add exports of a module as style to DOM입니다. 해석하면 DOM의 <style></style> 안으로 넣어줍니다. 이런 기능이기 때문에 js와 scss만 번들 작업을 해야하는 상황에선 필요 없습니다.

Q. sass-loader가 먼저 실행되어야 할 것 같은데, css-loader 보다 뒤에 있는 이유는 무엇인가요?

A. rules > use의 실행 순서는 맨 끝 부터 시작하여 처음으로 갑니다.

Plugins

Loaders에서 .scss에 대한 webpack의 작업 방식을 설정하였는데요.

현재 상태는 .scss만 이해하고 .css 파일로 내보내지는 못합니다.

Plugins 목록

이런 역할을 하는 plugin이 하나 있습니다.

npm i mini-css-extract-plugin -D

mini-css-extract-plugin docs를 보고 설정을 바꿔봤습니다.

📚 webpack.config.js
          👇
...
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = (webpackEnv) => {
  return {
    ...
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
        },
      ],
    },
    plugins: [new MiniCssExtractPlugin()],
  };
};

여기서 잠깐!

Q. 다른 블로그들 보면 extract-text-webpack-plugin을 사용하는데, mini-css-extract-plugin을 사용하시는 이유가?

A. extract-text-webpack-plugin github을 확인해보면 deprecated 되었다는 것을 알 수 있습니다.

Please use: https://github.com/webpack-contrib/mini-css-extract-plugin

If you have problem(s) with migration on MiniCssExtractPlugin feel free to open issue with reproducible test repo, thanks

npm script

webpack command-line docs에 모든 cli 옵션이 적혀있습니다.

이제 js / scss를 수정할 때마다 변경 사항을 감지해서 bundle하는 스크립트production level로 bundle하는 스크립트가 필요합니다.

📚 package.json
        👇
"scripts": {
  "build": "webpack -p --progress --env production",
  "start": "webpack -d --env development -w"
 },

📌 options
      👇
--watch, -w : 파일 변화 감지
--env larry : webpack.config.js에 환경변수 전달 >> "larry"
--env.name=larry : webpack.config.js에 환경변수 전달 >> { name: "larry" }

📌 shortcuts
       👇
-d : --debug --devtool cheap-module-eval-source-map --output-pathinfo
-p : --mode production

테스트

지금까지는 webpack의 설정만 다뤄서 실제 웹팩이 작업할 파일은 아무것도 없는 상태입니다.

그래서 필자가 테스트 용도로 하나 만들어봤습니다.

📚 assets/js/main.js
          👇
import "../scss/styles.scss";
-------------------------------
📚 assets/scss/_colors.scss
            👇
$dark: #303030;
$light: #e7e8e9;
-------------------------------
📚 assets/scss/home.scss
            👇
.style {
  font-size: 20px;
  & span {
    font-weight: 600;
    color: $dark;
  }
}

h1 {
  color: peru;
}
-------------------------------
📚 assets/scss/styles.scss
             👇
@import "./_colors.scss";
@import "./home.scss";

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

이제 start 스크립트를 실행해봅니다.

npm start

정상 동작하면 다음과 같은 화면을 볼 수 있습니다.

html을 작성해서 스타일링이 제대로 되었는지 확인해봅니다.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Webpack App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <link href="main.css" rel="stylesheet" />
  </head>
  <body>
    <span class="style">Larry <span>Jung</span></span>
    <h1>This is H1</h1>
    <script src="my-first-webpack.bundle.js"></script>
  </body>
</html>

결과

postCSS

일단 styles.scss 내용을 바꾸겠습니다

지금까지는 npm run prod-asset을 입력하면 다음의 결과물이 나옵니다.

# main.css
.example {
  display: grid;
  transition: all 0.5s;
  user-select: none;
  background: linear-gradient(to bottom, white, black);
}

이 상태로는 다양한 브라우저(Chrome, Firefox, ...)를 지원할 수 없습니다.

다양한 브라우저를 지원해야할 때, postCSSautoprefixer를 사용합니다.

autoprefixer를 사용하기 위한 핵심 패키지를 설치합니다.

npm i postcss-loader autoprefixer -D

webpack > autoprefixing docs를 보았는데, 필자가 따라 해도 작동이 안 돼서 대안을 찾아냈다.

postcss.config.js

프로젝트 디렉터리에 postcss.config.js라는 파일을 만든 뒤, 다음 구문을 붙여넣습니다.

📚 postcss.config.js
          👇
module.exports = {
  plugins: [require("autoprefixer")],
};

webpack.config.js

일단 scss를 번들하는 과정은 다음과 같습니다.

  1. scss를 불러와서 컴파일합니다. (sass-loader)
  2. 컴파일한 css를 불러옵니다. (css-loader)
  3. MiniCssExtractPlugin.loader로 불러온 뒤 플러그인으로 .css 파일을 내보냅니다.

그렇다면 postcss-loader는 어디에 들어가야 할까요?

1번과 2번 사이입니다.

📚 webpack.config.js
           👇
module.exports = (webpackEnv) => {
  return {
    ...
    module: {
      rules: [
        {
          test: /\.scss$/,
          use: [
            MiniCssExtractPlugin.loader,
            "css-loader",
            {
              loader: "postcss-loader",
              options: {
                config: { path: "postcss.config.js" },
              },
            },
            "sass-loader",
          ],
        },
      ],
    },
  };
};

package.json

browserslist는 어떤 브라우저까지 지원할 지 preset을 정합니다.

사용 가능한 preset은 browserslist full list에서 확인이 가능합니다.

또한, browserslist queries를 보면 다음과 같이 적혀있습니다.

browserslist key in package.json file in current or parent directories. We recommend this way.

browserlist는 package.json 안에 설정하는 것을 추천한다는 내용입니다.

필자는 호환성이 제일 좋은 cover 99.5% 옵션을 사용했습니다.

📚 package.json
        👇
{
  ...
  "browserslist": [
    "cover 99.5%"
  ]
}

실행

npm run dev-asset

Google Chrome(webkit), Firefox(moz), IE(ms) 모두 지원하는 것을 볼 수 있습니다.

Babel

📌 https://webpack.js.org/loaders/babel-loader/#root

SCSS는 물론 JS도 트랜스파일 및 번들 작업이 하고 싶으시다면 이 항목을 따라합니다.

필요한 패키지 설치

npm i babel-loader -D

module > rules 작성

module.exports = (webpackEnv) => {
  return {
    ...
    module: {
      rules: [
        {
          test: /\.(js|mjs|jsx|ts|tsx)$/,
          use: "babel-loader",
          include: path.resolve(__dirname, "src"),
        },
      ],
    },
  };
};

github

https://github.com/Kunune/webpack-with-scss

0개의 댓글