자바스크립트에서 css 파일을 모듈로 불러올 수 있는 기능을 제공한다.
import * as math from "./math_amd.js";
import "./app.css";
console.log("1+2 = ", math.sum(1, 2));
css-loader
를 이용하면, 위와 같이 app.css
를 import
할 수 있다.
.text-blue {
color: blue;
}
위는 예시로 작성한 css이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>테스트용</title>
</head>
<body>
<span class="text-blue">콘솔을 확인해봅시다.</span>
<script src="./dist/main.js"></script>
</body>
</html>
span
태그에 class="text-blue"
를 넣어서 기존 글씨 색을 파란 색으로 바꿔보자.
npm run build
결과 위와 같이 에러가 난다.
ERROR in ./src/app.css 1:0
Module parse failed: Unexpected token (1:0)
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
> .text-blue {
| color: blue;
| }
@ ./src/app_amd.js 2:0-19
이 파일 타입을 다루기에 적절한 로더가 필요할 것 같다고 에러 메시지를 띄워준다.
npm install css-loader
위 명령어로 css-loader를 설치하자.
// node.js의 CommonJS 를 사용한 모듈화
const path = require("path");
module.exports = {
mode: "development",
entry: {
main: "./src/app_amd.js",
},
output: {
path: path.resolve("./dist"),
// output 이름을 동적으로 나타낼 수 있는 효과가 있다.
// entry는 하나가 아니라 여러 개일 수도 있어서,
// entry가 여러 개라면 output도 여러 개다.
filename: "[name].js",
},
module: {
rules: [
{
test: /\.css$/,
use: [
'css-loader'
],
},
],
},
이전에 직접 만든 loader
를 적용할 때와 비슷한데, 이번에는 경로에 그냥 'css-loader'
를 입력해주었다. 그리고 받아서 번들링 할 확장자를 .css
로 정해주었다.
이 과정에서 웹팩도 5버전으로 업그레이드했다.
엥? 분명 css 파일도 번들링 했는데 화면이 똑같다.
분명 main.js
에는 내가 작성한 css가 올바르게 번들된 것 같다. 왜 적용이 안 됐을까?
아직 CSSOM이 된 게 아니라, 자바스크립트 파일 내용에만 CSS가 있어서 적용이 되지 않았다.
고로 우리는 어떻게든 번들링된 결과를 CSSOM으로 변환시켜주어야 한다. 일반적으로 CSSOM을 생성하려면 HTML에서 CSS를 직접 불러와야 한다.
하지만 웹팩의 style-loader
를 이용해도 된다.
이전에도 설명했듯, 번들된 css를 CSSOM(CSS Object Model)으로 변경시키기 위해서 필요하다.
npm install style-loader
// node.js의 CommonJS 를 사용한 모듈화
const path = require("path");
module.exports = {
mode: "development",
entry: {
main: "./src/app_amd.js",
},
output: {
path: path.resolve("./dist"),
// output 이름을 동적으로 나타낼 수 있는 효과가 있다.
// entry는 하나가 아니라 여러 개일 수도 있어서,
// entry가 여러 개라면 output도 여러 개다.
filename: "[name].js",
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 로더의 실행 순서는 뒤에서부터 앞이다.
"style-loader",
"css-loader",
],
},
],
},
};
css-loader
의 위에 style-loader
도 추가했다. 참고로 로더의 실행 순서는 뒤에서부터 앞이다. stack에서 pop연산과 비슷하게 생각하자.
css가 잘 적용되었다.
head
태그 부분에 style
태그가 잘 들어간 것을 확인할 수 있다.
로더는 처음에 설명했듯, 사실 소스코드에서 사용하는 모든 파일을 모듈로 사용하게끔 만들 수 있다. CSS에서도 url()
함수에 이미지 파일 경로를 지정할 수 있다. 앞서 말한 경우들에 웹팩 4버전의 경우, file-loader
웹팩 5버전의 경우 asset/resource
를 이용하여 파일을 처리한다.
위와 같이 이전에 생성했던 app.css
에 background-image
를 추가해서 번들링해보자. npm run build
명령어를 입력하면 된다.
아무것도 설정 안했는데 자동으로 된다! 이게 어떻게 된 일일까?
webpack5
에서는 css에서 사용되는 이미지 번들링을 자동으로 지원한다.
import * as math from "./math_amd.js";
import "./app.css";
import image from "./image.png";
console.log("1+2 = ", math.sum(1, 2));
console.log("image", image);
위와 같이 ./image.png
파일을 image
라는 변수로 받아서 출력해보고 싶다.
이건 잘 안 된다.
// node.js의 CommonJS 를 사용한 모듈화
const path = require("path");
module.exports = {
mode: "development",
entry: {
main: "./src/app_amd.js",
},
output: {
path: path.resolve("./dist"),
// output 이름을 동적으로 나타낼 수 있는 효과가 있다.
// entry는 하나가 아니라 여러 개일 수도 있어서,
// entry가 여러 개라면 output도 여러 개다.
filename: "[name].js",
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 로더의 실행 순서는 뒤에서부터 앞이다.
"style-loader",
"css-loader",
],
},
{
test: /\.png$/,
type: "asset/resource",
},
],
},
};
공식문서에 의하면, 더이상 웹페이지에 사용되는 이미지 파일 같은 리소스는 use: ["file-loader"]
를 안써도 된다고 나온다. 대신에 위와 같이 type: "asset/resource"
라고 하면 된다고 나와있다.
웹팩 공식 홈페이지에서 위와 같이 검색하여 여러가지 정보를 찾아볼 수 있다.
정상적으로 잘 실행된다.
콘솔에서 이미지 경로를 잘 출력해주고 있다. 정상적으로 적용됐다.
웹팩의 결과물을 보면, 이미지 이름이 해쉬로 저장되어 있다. 해쉬로 저장되는 이유는 캐시를 피하기 위함이다. 이름이 같은 채로 파일 내용이 달라지면, 캐싱된 것을 그대로 불러올 수도 있다.
그 이유는 브라우저는 특정 시간 내에 다시 같은 페이지를 접속했을 때, 서버에 리소스 요청을 하는 대신에 캐시에 있는 리소스들을 활용한다. 웹사이트를 이용하다가 인터넷을 끊고 새로고침을 해도 몇몇 이미지는 그대로 보이는 현상을 경험해본적이 있을 것이다.
그래서 이러한 캐싱은 보통 URI를 기반으로 동일한 URI에 접속했을 때 이루어지기 때문에, 쿼리스트링을 활용하여 쿼리스트링에 절대 겹칠 수 없는 Hash나 UUID등의 유니크한 값을 넣어 캐싱을 막는다.
그러면 브라우저에 다운로드한 파일을 무시하고 서버로 새로운 요청을 보내게 된다.
이것을 캐시 무력화라고 부르기도 한다.
위의 내용을 적용하기 위해서는 웹팩 설정에서 다음과 같은 부분을 추가해주면 된다
웹팩 5의 경우
...
{
test: /\.png$/,
type: "asset/resource",
generator: {
filename: "static/[name][ext]?[hash]",
},
},
...
마지막에 ?[hash]
를 통해 쿼리스트링이 포함된 경로를 지정할 수 있다.
결과는 위와 같이 image.png?해쉬
가 된다.
웹팩 4의 경우
{
test: ...,
loader: 'file-loader',
options: {
publicPath: './dist/',
name: '[name].[ext]?[hash]'
}
}
웹팩 4의 경우, 거의 흡사한데 아주 약간 다르다
{
test: /\.(png|jpg|gif|svg)$/,
// type: "asset/inline",
type: "asset/resource",
generator: {
filename: "static/[name][ext]?[hash]",
},
},
보통 png
만 asset/resource
로 처리하는 것이 아니라, png
, jpg
, gif
, svg
를 전부 asset/resource
로 처리한다.
url-loader
는 보통 작은 이미지 등을 사용할 때, Data URI Scheme
방식을 이용하여 넣는 것을 말한다. Data URI Scheme
방식을 이용하면 리소스를 외부에서 가져오지 않고, 파일 자체를 문서에 임베드 시킨다.
data:[<media type>][;base64],<data>
와 같은 형태로 이루어진다.
text/plain;character=US-ASCII
가 적용된다. {
test: /\.(png|jpg|gif|svg)$/,
type: "asset/inline",
// type: "asset/resource",
// generator: {
// filename: "static/[name][ext]?[hash]",
// },
},
기존의 설정을 asset/resource
에서 asset/inline
으로 바꿔보았다.
이미지가 1.1MB의 거대한 문자로 변했다. 이 문자가 Data URI Scheme
이며, 이 문자를 이용해 HTML 문서에 이미지를 임베드 할 수 있다.
{
test: /\.(png|jpg|gif|svg)$/,
loader: "url-loader",
},
url-loader
는 웹팩 4에서만 사용하는데, 위와 같이 사용하면 된다.
{
test: /\.(png|jpg|gif|svg)$/,
type: "asset",
parser: {
dataUrlCondition: {
maxSize: 4 * 1024, // 4kb
},
},
},
위와 같이 "asset"
타입으로 한 뒤에 parser
에 사이즈의 제한을 걸어두면, 해당 사이즈 미만은 asset/inline
으로 처리하고, 해당 사이즈 이상은 asset/resource
로 처리해서 네트워크 연결 오버헤드가 더 클만한 파일은 문서에 임베딩 시키고, 네트워크 연결 오버헤드가 더 크지 않은 큰 이미지 파일은 리소스로 관리하여 가성비를 챙길 수 있다.
큰 이미지는 리소스로 관리되고, 작은 이미지는 Data URI Scheme
으로 관리되는 것을 볼 수 있다.
webpack.config.js
에 module: { rules:[] }
에 위치하게 된다.test
에 정규표현식으로 어떤 파일 이름 패턴에 적용할지 정할 수 있다.use
에 의존성으로 추가한 로더(css-loader
, style-loader
)를 입력해 이용할 수 있다.type
에는 웹팩5에서 지원하는 로더(asset
, asset/resource
, asset/inline
)를 입력해 이용할 수 있다.asset/resource
, 웹팩 v4에서는 file-loader
를 사용하면 된다.asset/inline
, 웹팩 v4에서는 url-loader
를 사용하면 된다.asset
이라는 타입 하나로 전부 로드할 수 있다.css-loader
와 로드한 CSS를 CSSOM(CSS Object Model) 로 만들어주는 style-loader
가 필요하다.module: { rules: [ { ... use: "style-loader", "css-loader" } ] }
와 같은 형식으로 입력하면 된다. use
에 등록된 로더의 실행순서는 뒤에 있는 로더가 먼저 실행되기 때문에, 반드시 css-loader
가 뒤로 가야 한다.
와 진짜 설명 잘해주시네요. 감사합니다!