webpack 설정하기 loader, plugin

 

Webpack 개념에서 실무활용까지 -1 탄에서는 js, css, html까지만 번들링했는데 이번엔 자주 사용하는 loader와 plugin의 사용법에 대해 알아보자.

 

1. balel-loader 

babel은 최신 javascript 코드를 구형 브라우저에서도 호환되도록 변환하는 역할을 한다. 개발자는 최신 기능(es6 +)을 사용해도 다양한 환경에서 애플리케이션이 정상적으로 작동하도록 해줌. (ES6 + -> ES5로 변환한다.)

필수 loader라 1번으로 설정해준다.

 

설치 후 module에 아래와 같이 작성한다.

(webpack babel-loader docs)

npm install -D babel-loader @babel/core @babel/preset-env webpack
module: {
  rules: [
    {
      test: /\.(?:js|mjs|cjs)$/,
      exclude: /node_modules/, // node_modules 은 변환하지 않는다
      use: {
        loader: 'babel-loader',
        options: {
          presets: [
            ['@babel/preset-env', { targets: "defaults" }]
          ]
        }
      }
    }
  ]
}

 

2. file-loader

image, font 등의 asset 파일을 type 경로에 복사해준다. 파일 경로가 자동으로 관리되므로 가독성과 유지보수가 좋아진다

webpack5 부터는 별도로 설치 안해도 된다.

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/i, // 이미지 파일 처리
        type: 'asset/resource', // 파일을 복사해 해당 경로에 저장
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i, // 폰트 파일 처리
        type: 'asset/resource', 
      },
    ],
  },
};

 

3. sass-loader ()

scsss/sass 파일을 css로 변환

 

설치 ( webpack sass-loader docs)

npm install sass-loader sass webpack --save-dev
module.exports = {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/i,,
        use: [
          "style-loader", "css-loader" // 기존의 css loader
          "sass-loader", // sass-loader 추가!
        ],
      },
    ],
  },
};

 

4. MiniCssExtractPlugin

1탄에서 설명하 html 파일처럼 css 파일을 별도의 파일로 추출한다.

production용으로 빌드하는 경우엔 js와 병렬 로딩이 가능하도록 css를 별도로 추출하는것이 좋다.

docs에는 style-loader와 함께 사용하지 말라고 권장하니 아래와 같이 사용해보자. (관련 git docs)

npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const devMode = process.env.NODE_ENV !== "production";

module.exports = {
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/i,
        use: [
          devMode ? "style-loader" : MiniCssExtractPlugin.loader, // mode에 따라 다르게 실행해준다
          "css-loader",
          "sass-loader",
        ],
      },
    ],
  },
  plugins: [].concat(devMode ? [] : [new MiniCssExtractPlugin()]), // plugin 사용법
};

 

5. dotenv-webpack (feat .env)

.env 파일에 작성한 환경변수도 아래와 같이 번들해주면 웹 브라우저에서도 사용 가능하다.

// .env 파일

API_URL: localhost:5500
NODE_ENV: development
const Dotenv = require("dotenv-webpack");

module.exports {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
  },
  plugins: [
    new Dotenv(), // .env 파일을 읽도록 설정
  ],
};

 

또는 아래와 같이 각각 설정해준다

const webpack = require('webpack');
const dotenv = require('dotenv');

dotenv.config(); // .env 파일 변수를 가져온다

module.exports = {
  plugins: [
    new webpack.DefinePlugin({ webpack.DefinePlugin 으로 하나하나 정의한다.
      'process.env.API_URL': JSON.stringify(process.env.API_URL),
      'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
    }),
  ],
  mode: process.env.NODE_ENV || 'development',
};

 

그럼 아래와 같이 웹브라우저에서 구동하는 js파일에서 사용 가능하다.

 

// index.js

console.log(process.env.API_URL) // localhost:5500
console.log(process.env.NODE_ENV) // development

 

6. typescript 설정

typescript 를 사용한다면 아래와 같이 babel도 함께 작성하면 좋다.

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: [
          {
            loader: 'babel-loader', // Babel을 먼저 실행
            options: {
              presets: ['@babel/preset-env', '@babel/preset-typescript'], // TypeScript와 ES6+ 지원
            },
          },
          'ts-loader', // TypeScript 처리
            ],
            exclude: /node_modules/,
          },
        ],
      },
  }

 

그리고 build용량 줄이려고 webpack 많이 사용하는데 mode 지정에 따라 아래의 설정이 자동으로 적용된다.

 

mode: development

 - 소스 맵 생성, 코드 압축 비활성화(디버깅 용이), 경고 메시지 활성화 등 개발에 최적화된 기본 설정

mode: production

 - 코드 압축, 최적화, 트리 셰이킹 등 프로덕션에 최적화된 기본 설정

 

3탄은 회사에서 진행했던 electron webpack 설정과 배포 자동화까지의 내용을 담으려 합니당

읽어주셔서 감사합니다.👩‍💻

'Webpack' 카테고리의 다른 글

Webpack 개념에서 실무활용까지 -1  (0) 2024.08.21
webpack 이 뭐에요?

 

webpack은 최신 자바스크립트 애플리케이션을 위한 정적 모듈 번들러입니다. (webpack 공식 정의)

정의는 역시 잘 와닿지 않죠.

 

그럼 모듈은 뭐고 번들은 뭘까?

 

모듈은 기능을 가진 (작은) 코드 단위이다. 대규모 애플리케이션에서 모듈화는 관리와 유지보수를 쉽게 해주고, 코드의 재사용성을 높이고 협업에 도움을 준다. 

// 작게는 아래 함수부터
function sum(a, b) {
  return a + b;
}

// 일반적으로 많이 사용하는 node_modules 에서 불러오는 것들 (패키지 기반 모듈)
import path from 'path'; 경로를 쉽게 설정할 수 있게 해주는 path 모듈

// 또는 HTML, CSS, Js, Images 파일들 하나하나도 모듈이다 (파일 기반 모듈)
index.html
main.css
main.js
image.jpg

 

모듈은 관리하기 위한 시스템이 존재하는데 대표적으로는 CommonJS, ES6 모듈 시스템이 있다.

CommonJS) require module.exports 를 사용해 모듈을 가져오고 내보낸다.

ES6) import export 로 모듈을 가져오고 내보낸다.

 

번들은 관련 파일들을 하나로 묶어주는 것인데 (연필 12개를 한다스로 묶듯이)

모듈 번들러는 웹 애플리케이션을 구성하는 여러 모듈(파일 등)을 하나의 파일로 묶고 압축해주는 것을 모듈 번들링이라고 한다. (흔히 빌드한다고 하는데 번들링과 같은 말임)

webpcak docs 중 발췌

 

webpack 어디다 쓰나요?

 

웹팩은

1. 자바스크립트 모듈(파일)들의 관리와 

2. 웹 애플리케이션 빠른 로딩 속도와 성능

등의 이점이 있다.

 

1. 자바스크립트 모듈(파일)들의 관리

react, next.js는 자동으로 webpack 설정을 해줘서 종종 잊지만 한번씩 html, css, js 파일로 작은 애플리케이션을 만들다 보면 webpack 설정은 필요하다.

 

아래 번들링 없이 전역 변수를 사용하는 예시를 보자.

hello.js, world.js 파일을 불러와 innerHTML에 파싱한다

// index.html
<html>
    <body>
      <h1>hello, webpack!</h1>
      <div id="root"></div>
        <script src="./src/hello.js"></script>
        <script src="./src/world.js"></script>
        <script>
          document.getElementById('root').innerHTML = v; // world 만 출력 
        </script>
    </body>
</html>

// hello.js
var v = "Hello";

// world.js
var v = "world";

 

결과는 늦게 가져온 world.js 값만 파싱되었다 (덮어 씌워짐)

변수의 유효 범위 때문에 전역 변수의 예상치 못한 충돌이 발생한다.

 

-> ES6 모듈 시스템을 사용해 이름 충돌을 피할 수 있다. 

<script type="module">
  import v_hello from './src/hello.js';
  import v_world from './src/world.js';
  document.getElementById('root').innerHTML = v_hello + " " + v_world; // hello world 출력
</script>

위와 같이 ES6 모듈만 사용해도 전역 변수 충돌 해결된다.

하지만 webpack을 사용하면 더 깔끔하게 관리 가능하다.

 

index.js 파일에 위 코드를 작성하고 

// index.js
import v_hello from './hello.js';
import v_world from './world.js';

document.getElementById('root').innerHTML = v_hello + " " + v_world;

 

webpack으로 번들링해보자.

그리고 index.html 의 script 파일 경로를 번들링된 js로 변경

// index.html

<body>
  <h1>hello, webpack!</h1>
  <div id="root"></div>
  <script src="./build/main.js"></script> // bundle 된 js 파일 경로
</body>

이렇게 하면 위의 기능과 동일하게 root 안에 hello world 가 출력된다.

-> webpack을 통해 2개의 js파일을 하나로 관리하고 import export 로 전역 변수 충돌문제를 해결하는 es6 모듈 시스템을 더욱 잘 관리할 수 있게됐다. 

 

물론 요새는 var 사용 안하기도 하고 예시가 잘 와닿지 않을 수 있지만 위와 같은 번들링이 없던 시절엔 점점 규모가 커지면서 위의 전역변수 충돌, 모듈 관리의 문제점이 있었고 이를 방지하기 위해 여러 방법 중에 하나인 웹팩이 등장했다고한다.

 

+ react에 설정된 자동 번들러없이 js 파일 만들때 아래 에러 한번씩은 만나봤을겁니다..


Uncaught TypeError: Failed to resolve module specifier "lodash". Relative references must start with either "/", "./", or "../". 

// hello.js

import _ from "lodash"; // react에서 처럼 그냥 이렇게 node_modules 에서 가져오면 에러남

var v = _.join(["Hello", " ", "world"], ""); // Hello world

 

위와 같이 상대 경로로 가져오라는 에러가 나는데 웹 브라우저는 기본적으로 상대 경로로 시작하는 경로만 지원하고

빌드없이 해당 모듈을 불러오려면 import _ from "../node_modules/lodash/lodash.js" 요런식으로 해야되는 번거로움이 발생한다. (빌드 후에는 최종 파일에 lodash 와 같은 import 한 모듈이 포함되어 있어 바로 접근 가능한것)

이와같이 개발 과정에서 빌드 도구를 사용하면 모듈 관리를 편하게 할수있다.

 

2. 웹 애플리케이션 빠른 로딩 속도와 성능

많은 js 파일을 하나의 js 파일로 묶어서 압축해주기 때문에 용량이 작아져 웹 브라우저가 빨리 읽을수 있고 

여러 HTTP 통신을 줄여줘 웹 애플리케이션 성능을 높여줌. 

 

간단한 예제

webpack 과 webpack-cli 설치

webpack-cli 를 통해 npx webpack, npx webpack server 등의 명령어를 사용할 수 있다

npm init
npm install webpack webpack-cli --save-dev

 

// package.json

// script는 취향에 따라 커스텀해준다
"scripts": {
  "build": "npx webpack --watch" // 해당 명령어는 바라보는 js 파일이 변하면 다시 build 해줌
}
// webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.js', // 해당 경로 index.js을 build 해서
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'), // 해당 경로에 main.js 로 output 해준다
  },
};

// entry 와 output 은 위 설정이 default 지만 여러 프로젝트마다 폴더구조도 다르고하니 알아두자

 

css 번들 

css도 js 파일로 함께 말수있다. 

 

css 관련 모듈 설치

npm install --save-dev css-loader
npm install --save-dev style-loader
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.css$/i, // 파일 확장자가 .css로 끝나는 모든 파일을 build 한다
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

loader는 파일을 전처리 시켜준다. loader를 통해 js 파일만이 아닌 자산(css, image, json 파일 등등)을 번들링 할 수 있다.

(css -> js, image -> base64 로 변환)

 

html도 함께 번들링해야 배포하기 편함

const HtmlPlugins = require("html-webpack-plugin");

module.exports = {
  plugins: [ // css와 다르게 plugins에서 인스턴스를 실행한다
    new HtmlPlugins({
      filename: "index.html", // output 시 파일명
      template: "./src/index.html", // input html 경로
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

로더는 특정 유형의 모듈(css, image)을 변환하고, 플러그인은 번들을 최적화하거나, 에셋 관리, 환경 변수 주입 등의 다양한 작업을 할 수 있다. (HTML 파일 생성, 코드 압축, .env 파일의 환경 변수 주입 등)

'Webpack' 카테고리의 다른 글

Webpack 개념에서 실무활용까지 -2  (0) 2024.08.21

+ Recent posts