[Webpack5] loader와 asset modules

상민·2022년 7월 19일
0
post-thumbnail

로더

로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환해 주거나 이미지를 data URL 형식의 문자열로 변환한다.
뿐만 아니라 CSS 파일을 자바스크립트에서 직접 로딩할 수 있도록 해준다.


커스텀 로더 만들기

로더를 테스트 해보기 위해 my-webpack-loader.js 파일을 만들고 아래 함수를 선언한다

  • my-webpack-loader.js

module.exports = function myWebpackLoader(content) {
  console.log("로더 실행됨");
  return content;
};

로더가 작동했는지 확인하기 위해 console.log를 찍는다

로더를 실행하기 위해 webpack.config.js 파일을 아래처럼 수정한다

  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [path.resolve("./my-webpack-loader.js")],
      },
    ],
  },
};

로더는 module객체의 rules 배열형태로 추가할 수 있다

rules 배열에는 객체를 넣을 수 있는데 testuse라는 두 키를 갖는 객체를 쓴다.
test에는 로더가 처리해야 하는 파일들의 패턴을 입력(정규표현식)
use배열에는 사용할 로더를 명시한다

npm run build
> webpack-babel-practice@1.0.0 build
> webpack

로더 실행됨
로더 실행됨
asset main.js 4.55 KiB [emitted] (name: main)
runtime modules 670 bytes 3 modules
cacheable modules 544 bytes
  ./src/app.js 224 bytes [built] [code generated]
  ./src/math.js 320 bytes [built] [code generated]
webpack 5.73.0 compiled successfully in 49 ms

콘솔에 "로더 실행됨"이 잘 나오는 것을 보아 로더가 잘 실행되었음을 확인할 수 있다
로더가 두번 실행되는데 그 이유는 각 파일별로 로더가 처리했기 때문이다
모든 자바스크립트 파일마다 로더가 한번씩 실행되도록 했기 때문에 두번 찍힌 것이다

이번에는 모든 console.log를 alert로 변환하는 것을 해보자

  • my-webpack-loader.js

module.exports = function myWebpackLoader(content) {
  return content.replaceAll("console.log(", "alert(");
};

다시 npm run build 명령어를 입력해 웹팩을 통해 번들링 작업을 한다

npm run build

브라우저에서 index.html을 열어서 확인해보면 이전에는 콘솔에 3이 출력되던 것이 alert창에 3이 출력되는 것을 확인할 수 있다


자주 사용하는 로더

css-loader

css-loaderCSS파일을 모듈로 변환하는 작업을 한다
그러면 코드에서 CSS파일을 모듈처럼 불러와 사용할 수 있다

app.js에서 import './app.css'를 불러오려면 css파일을 모듈로 불러와야 한다
우선 css-loader 없이 한번 작성해보겠다

  • src/app.css

body {
  background-color: green;
}
  • src/app.js

import "./app.css";
> webpack-babel-practice@1.0.0 build
> webpack

asset main.js 4.6 KiB [emitted] (name: main)
runtime modules 937 bytes 4 modules
cacheable modules 55 bytes
  ./src/app.js 20 bytes [built] [code generated]
  ./src/app.css 35 bytes [built] [code generated] [1 error]

ERROR in ./src/app.css 1:5
Module parse failed: Unexpected token (1:5)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> body {
|   background-color: green;
| }
 @ ./src/app.js 1:0-19

webpack 5.73.0 compiled with 1 error in 43 ms

이대로 npm run build를 실행하면 오류가 나는데 웹팩이 css파일을 읽다가 무슨말인지 몰라서 에러를 내는 것이다
결국 자바스크립트에서 사용하려면 모듈로 만들어 줘야 한다

먼저 로더를 설치 하자

npm install -D css-loader
  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["css-loader"],
      },
    ],
  },
};

커스텀 로더 설정했던것을 지우고 css파일을 읽도록 변경하고 css-loader 추가한다

다시 빌드해보면 적용이 잘 된다

번들링 된 main.js를 보면 css코드가 js파일에 포함되어 있는 것을 확인할 수 있다

하지만 브라우저에서 확인해 보면 css가 적용이 안되어있다

css코드가 CSSOM 형태로 바뀌어야만 브라우저에 모습을 드러낸다
그렇게 하려면 html에서 css코드를 직접 불러오거나 inline-script로 넣어주어야 하는데 그런 처리를 해주지 않고 자바스크립트 코드에만 css코드가 있기 때문이다

그래서 나온 것이 style-loader

style-loader

style-loader자바스크립트로 변경된 스타일 코드를 html에 넣어주는 역할을 한다
따라서 css-loader와 style-loader를 같이 사용해야 한다

npm install -D style-loader
  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

use 배열에 style-loader 추가한다
순서는 뒤에서부터 앞에니까 style-loader를 css-loader보다 앞에 써줘야 한다

저장하고 다시 빌드하면 브라우저에 잘 적용되는 것을 확인할 수 있다

file-loader (webpack4)

로더는 css파일 뿐만 아니라 이미지 파일도 처리할 수 있다

import 구문으로 이미지 파일을 자바스크립트로 가져올 수 있다
css파일도 모듈로 처리하기 때문에 css에서 이미지 파일을 가져올 수 있다

src폴더에 bg.png파일을 추가하고 app.css 파일을 만들어 아래와 같이 작성한다

  • app.css

body {
  background-image: url(bg.png);
}
npm install -D file-loader
  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.png$/,
        use: ["file-loader"],
      },
    ],
  },
};

config파일에서 rules 배열에 객체를 하나 더 추가하고 test에 확장자가 png를 찾도록 추가하고 use 배열에 file-loader를 추가한다

build를 해보면 dist폴더에 이미지 파일이 추가된 것을 확인할 수 있다.
파일명이 해쉬 값으로 변경이 되어 있다
웹팩은 빌드를 할때마다 유니크한 값을 생성하는데 그것이 앞에있는 해쉬값이다

하지만 브라우저에서 확인해 보면 적용이 되어 있지 않다
콘솔에 오류가 뜨는데 파일을 못찾았다는 에러가 뜬다

이미지 파일이 html과 같은 폴더에 있는 것이 아니라 src 안에 있기 때문 그래서 파일을 못 찾는 것이다

웹팩 설정파일을 아래와 같이 수정해보자

  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.png$/,
        loader: 'file-loader',
        options: {
          publicPath: './dist',
          name: '[name].[ext]?[hash]'
        }
      },
    ],
  },
};

publicPath는 file-loader가 처리하는 파일을 모듈로 사용했을때 경로 앞에 추가되는 문자열이다
파일을 호출하는 측에서는 경로 앞에 dist를 붙히고 파일을 호출할 것이다

name은 file-loader가 파일을 output에 복사할 때 사용하는 파일 이름이다
원본 파일명과 확장자명을 사용한다

다시 빌드하고 dist폴더를 확인하면 bg.png가 있는 것을 확인할 수 있다
브라우저에서도 적용이 잘 되어 있다

url-loader (webpack4)

사용하는 이미지 갯수가 많다면 네트워크 리소스를 사용하는 부담이 있고 사이트 성능에 영향을 줄 수도 있다
만약 한 페이지에서 작은 이미지를 여러개 사용한다면 Data URI Scheme을 이용하는 방법이 더 낫다
이미지를 Base64로 인코딩하여 문자열 형태로 소스코드에 넣는 형식이다
url-loader는 이러한 처리를 자동화 해주는 역할을 한다

src폴더에 nyancat.jpeg파일을 추가하고 app.js를 아래와 같이 수정한다

  • src/app.js

import "./app.css";
import nyancat from "./nyancat.jpeg";

document.addEventListener("DOMContentLoaded", () => {
  document.body.innerHTML = `
    <img src="${nyancat}" />
  `;
});

이는 file-loader가 처리할 수도 있으니까 file-loader에서 이미지 확장자를 추가한다

  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        loader: "file-loader",
        options: {
          publicPath: "./dist",
          name: "[name].[ext]?[hash]",
        },
      },
    ],
  },
};

빌드하고 브라우저에서 확인하면 잘 출력되는 것을 확인할 수 있다

nyancat.jpeg 이미지 크기를 확인해보면 18K이다

이를 파일을 옮길 필요없이 바로 base64로 인코딩해서 넣어보겠다

npm install -D url-loader
  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        loader: "url-loader",
        options: {
          publicPath: "./dist",
          name: "[name].[ext]?[hash]",
          limit: 20000 //20KB
        },
      },
    ],
  },
};

file-loaderurl-loader로 수정한다
optionslimit을 20000으로 설정하면 url-loader가 파일을 처리할 때 20KB 미만의 파일들은 url-loader를 통해 base64로 처리한다
그 이상은 file-loader가 처리할 것이다

빌드 후 dist폴더를 확인해보면 bg.png는 file-loader가 처리했고 nyancat.jpeg는 url-loader가 처리하여 main.js에 포함되어 있다

브라우저에서도 결과가 잘 출력되는 것을 확인할 수 있다


Asset Modules (webpack5)

asset modules로더를 추가로 구성하지 않아도 asset 파일 (폰트, 아이콘 등)을 사용할 수 있도록 해주는 모듈이다

webpack5 이전에는

  • raw-loader: 파일을 문자열로 가져올 때
  • url-loader: 파일을 data URI 형식으로 번들에 인라인 추가할 때
  • file-loader: 파일을 output 디렉터리로 내보낼 때

로더를 사용하는 것이 일반적이었다

webpack5에서는 이러한 로더를 대체하기 위해 asset module4개의 새로운 모듈 유형이 추가되었다

  • asset/resource: 별도의 파일을 내보내고 URL을 추출 (file-loader 대체)
  • asset/inline: asset의 data URI를 내보냄 (url-loader 대체)
  • asset/source: asset의 소스 코드를 내보냄 (raw-loader 대체)
  • asset: data URI와 별도의 파일 내보내기 중 자동으로 선택

asset을 이용해서 bg.png를 resource로, nyancat.jpeg를 inline으로 번들링 해보자

  • webpack.config.js

const path = require("path");
module.exports = {
  mode: "development",
  entry: {
    main: "./src/app.js",
  },
  output: {
    path: path.resolve("./dist"),
    filename: "[name].js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(png|jpg|jpeg|gif|svg)$/,
        type: "asset", // 40KB(default) 미만은 inline, 이상은 resource로 대처
        parser: {
          dataUrlCondition: {
            maxSize: 20 * 1024, // 기준을 20KB 로 변경
          },
        },
      },
    ],
  },
};

type"asset"으로 지정하여 40KB 미만의 파일은 inline으로, 이상은 resource로 대처하도록 했다
asset의 기본 기준은 40KB이지만 parser 객체의 dataUrlConditionmaxSize를 조절하여 기준값을 설정할 수 있다
기준을 20KB로 설정하고 다시 빌드를 해보자

.
├── dist
│   ├── 5c6d3b633991b51295c6.png
│   └── main.js
├── index.html
├── my-webpack-loader.js
├── package-lock.json
├── package.json
├── src
│   ├── app.css
│   ├── app.js
│   ├── bg.png
│   ├── math.js
│   └── nyancat.jpeg
└── webpack.config.js

20KB가 넘는 bg.png는 dist폴더에 생성되었고 20KB 미만인 nyancat.jpeg는 main.js에 inline으로 추가되었다

브라우저에서도 이미지가 잘 출력되는 것을 확인할 수 있다!

참고: https://jeonghwan-kim.github.io/series/2019/12/10/frontend-dev-env-webpack-basic.html
https://wnsah052.tistory.com/188

profile
FE Developer

0개의 댓글