로더는 타입스크립트 같은 다른 언어를 자바스크립트 문법으로 변환
해 주거나 이미지를 data URL 형식의 문자열로 변환
한다.
뿐만 아니라 CSS 파일을 자바스크립트에서 직접 로딩
할 수 있도록 해준다.
로더를 테스트 해보기 위해 my-webpack-loader.js 파일을 만들고 아래 함수를 선언한다
module.exports = function myWebpackLoader(content) {
console.log("로더 실행됨");
return content;
};
로더가 작동했는지 확인하기 위해 console.log를 찍는다
로더를 실행하기 위해 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 배열에는 객체를 넣을 수 있는데 test
와 use
라는 두 키를 갖는 객체를 쓴다.
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로 변환하는 것을 해보자
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파일을 모듈로 변환하는 작업을 한다
그러면 코드에서 CSS파일을 모듈처럼 불러와 사용할 수 있다
app.js에서 import './app.css'를 불러오려면 css파일을 모듈로 불러와야 한다
우선 css-loader 없이 한번 작성해보겠다
body {
background-color: green;
}
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
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
는 자바스크립트로 변경된 스타일 코드를 html에 넣어주는 역할
을 한다
따라서 css-loader와 style-loader를 같이 사용
해야 한다
npm install -D style-loader
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보다 앞에 써줘야 한다
저장하고 다시 빌드하면 브라우저에 잘 적용되는 것을 확인할 수 있다
로더는 css파일 뿐만 아니라 이미지 파일도 처리할 수 있다
import 구문으로 이미지 파일을 자바스크립트로 가져올 수 있다
css파일도 모듈로 처리하기 때문에 css에서 이미지 파일을 가져올 수 있다
src폴더에 bg.png파일을 추가하고 app.css 파일을 만들어 아래와 같이 작성한다
body {
background-image: url(bg.png);
}
npm install -D file-loader
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 안에 있기 때문 그래서 파일을 못 찾는 것이다
웹팩 설정파일을 아래와 같이 수정해보자
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가 있는 것을 확인할 수 있다
브라우저에서도 적용이 잘 되어 있다
사용하는 이미지 갯수가 많다면 네트워크 리소스를 사용하는 부담이 있고 사이트 성능에 영향을 줄 수도 있다
만약 한 페이지에서 작은 이미지를 여러개 사용한다면 Data URI Scheme
을 이용하는 방법이 더 낫다
이미지를 Base64
로 인코딩하여 문자열 형태로 소스코드에 넣는 형식이다
url-loader
는 이러한 처리를 자동화 해주는 역할을 한다
src폴더에 nyancat.jpeg파일을 추가하고 app.js를 아래와 같이 수정한다
import "./app.css";
import nyancat from "./nyancat.jpeg";
document.addEventListener("DOMContentLoaded", () => {
document.body.innerHTML = `
<img src="${nyancat}" />
`;
});
이는 file-loader가 처리할 수도 있으니까 file-loader에서 이미지 확장자를 추가한다
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
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-loader
를 url-loader
로 수정한다
options
에 limit
을 20000으로 설정하면 url-loader가 파일을 처리할 때 20KB 미만의 파일들은 url-loader를 통해 base64로 처리한다
그 이상은 file-loader
가 처리할 것이다
빌드 후 dist폴더를 확인해보면 bg.png는 file-loader가 처리했고 nyancat.jpeg는 url-loader가 처리하여 main.js에 포함되어 있다
브라우저에서도 결과가 잘 출력되는 것을 확인할 수 있다
asset modules
는 로더를 추가로 구성하지 않아도 asset 파일 (폰트, 아이콘 등)을 사용할 수 있도록 해주는 모듈이다
webpack5 이전에는
raw-loader
: 파일을 문자열로 가져올 때url-loader
: 파일을 data URI 형식으로 번들에 인라인 추가할 때file-loader
: 파일을 output 디렉터리로 내보낼 때로더를 사용하는 것이 일반적이었다
webpack5에서는 이러한 로더를 대체하기 위해 asset module
에 4개의 새로운 모듈 유형이 추가되었다
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
으로 번들링 해보자
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
객체의 dataUrlCondition
의 maxSize
를 조절하여 기준값을 설정할 수 있다
기준을 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