본문 바로가기

main/React

Babel과 Webpack의 내부 동작 이해하기 - 4 webpack

[실전 리액트 프로그래밍] webpack을 설치해보자!

 

👉🏻 webpack 실행해보기

웹팩은 웹에 들어가는 여러 가지 리소스를 사용자에게 전달하기 좋게 하나의 번들 형태로 만들어준다.

 

mkdir webpack-init
cd webpack-init/

npm init -y
{
  "name": "webpack-init",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

npm install webpack webpack-cli

webpack-cli를 이용하면 CLI에서 웹팩을 실행할 수 있다.

 

/util.js

export function sayHello(name) {
  console.log('hello', name);
}

 

/index.js

import { sayHello } from "./util";

function myFunc() {
  sayHello('mkie');
  console.log('myFunc');
}
myFunc();

 

cd ../  # 루트경로에서
npx webpack

파일을 생성하고 웹팩을 실행하면, dist 폴더가 만들어지고 그 안에 main.js 번들 파일이 생성된다.

index.js 모듈에서 util.js의 함수를 import, 사용했기 때문에 두 파일이 main.js 번들 파일로 합쳐졌다.

별다른 설정 없이 웹팩을 실행하면 ./src/index.js 모듈을 입력으로 받아서 ./dist/main.js 번들 파일을 만든다.

 

 

👉🏻 webpack.config.js 설정하기

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  mode: 'production',
  optimization: { minimizer: [] },
};

index.js 모듈을 입력 파일로 사용한다.

dist 폴더 아래 main.js 번들 파일을 생성한다.

production 모드는 js 코드 압축과 최적화 기능이 추가된다.

 

npx webpack

실행해 보면 main.js 는 다음과 같다.

/******/ (() => { // webpackBootstrap
/******/ 	"use strict";
var __webpack_exports__ = {};

;// CONCATENATED MODULE: ./src/util.js
function sayHello(name) {
  console.log('hello', name);
}
;// CONCATENATED MODULE: ./src/index.js


function myFunc() {
  sayHello('mkie');
  console.log('myFunc');
}
myFunc();
/******/ })()
;

 

 

로더 사용하기

👉🏻 자바스크립트 파일을 처리하는 babel-loader를 사용해보자.

npm install babel-loader @babel/core @babel/preset-react react react-dom

이는 JS코드에서 JSX 문법으로 작성된 리액트 코드를 처리하기 위해 필요한 패키지들이다.

 

/src/index.js

import React from 'react';
import ReactDOM from 'react-dom';

function App() {
  return (
    <div className="container">
      <h3 className="title">webpack example</h3>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'));

 

/webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
    ],
  },
  mode: 'production',
};

js 확장자를 갖는 모듈은 babel-loader가 처리하도록 설정한다.

 

/babel.config.js

const presets = ['@babel/preset-react'];
module.exports = { presets };

이 파일 없이 webpack을 실행시킬 경우 jsx문법을 이해하지 못하여 에러가 난다.

 

잘 실행될 경우

이런 이상한 코드가 나오게 되는데,

index.html에서 main.js를 script 코드로 입력해주고 vscode의 경우 <alt + B>로 브라우저에서 확인해보면

웹팩이 JSX를 잘 해석해서 보여주고 있는 것을 확인할 수 있다.

 

👉🏻 이제 css 파일을 처리하는 로더를 알아보자.

npm install css-loader style-loader

css 파일을 읽고 처리할 css-loader와 돔 요소에 실제로 스타일을 적용하기 위한 style-loader를 설치한다.

 

/src/App.css

.container {
  border: 1px solid skyblue;
}

.title {
  color: pink;
}

 

/src/index.js

import Style from './App.css';
console.log({Style});

css 파일을 사용하는 코드를 추가한다.

 

역시 이대로 npx webpack를 실행하면, css 로더가 없어서 에러가 발생한다.

 

/webpack.config.js

    ...
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader',
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
    ...

로더를 배열로 입력하면 오른쪽 로더부터 실행된다. css-loader가 먼저 데이터를 생성하지 않으면 style 태그가 삽입되지 않을 수 있다.

웹팩을 실행하고 브라우저에서 확인해보면 잘 처리된 것을 알 수 있다.

 

👉🏻 다른 종류의 기타 파일도 처리해 보자.

/src 폴더 아래에, *.png *.txt *.json 파일을 각각 만들었다.

 

/src/index.js

...
import Cat from './cat.png';
import Text from './data.txt';
import Json from './data.json';

function App() {
  return (
    <div className="container">
      <h3 className="title">webpack example</h3>
      <div>{`name: ${Json.name}, age: ${Json.age}`}</div>
      <div>{`text: ${Text}`}</div>
      <img src={Cat} />
    </div>
  )
}
...

index 파일에 사용할 코드를 추가해줬다.

 

npm install file-loader raw-loader

json 모듈은 웹팩에서 기본적으로 처리해 준다.

file-loader 는 모듈의 내용을 그대로 복사해서 dist 폴더에 복사본을 만들고, 모듈을 사용하는 쪽에 경로를 넘겨준다.

raw-loader 는 모듈의 내용을 그대로 자바스크립트 코드로 가져온다.

 

/webpack.config.js

      ...
      {
        test: /\.(png|jpg|gif)$/,
        use: 'file-loader',
      },
      {
        test: /\.txt$/,
        use: 'raw-loader',
      },
      ...

 

npx webpack 후 브라우저에서 확인

사진이 너무 크지만 잘 나오는 걸 확인할 수 있다.

 

👉🏻 마지막으로 이미지 파일의 요청 횟수를 줄여본다.

이미지 파일을 번들 파일에 포함시키면 브라우저의 파일 요청 횟수를 줄일 수 있다.

이때 번들 파일 크기가 너무 커지면 자바스크립트가 늦게 실행되므로, 작은 이미지 파일만 포함시키는 게 좋다.

npm install url-loader

 

/webpack.config.js

      {
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192,
            },
          },
        ],
      },

위에서 file-loader 부분을 url-loader로 수정했다.

만약 파일 크기가 8192보다 큰 경우 다른 로더가 처리할 수 있도록 fallback 옵션을 제공한다.

fallback 옵션을 입력하지 않으면 기본적으로 file-loader가 처리하게 되어 있다.

 

이미지를 번들 파일에 포함시키지 않고 경로로 요청
이미지를 번들 파일에 포함시켜 data로 보냄

 

기본적인 웹팩의 기능을 직접 구현해보면서 웹팩에 대한 이해도를 높였다.