요즘 회사에서는 Vue를 사용해 프로젝트를 진행하고 있습니다. 이번 1차 프로젝트가 곧 끝나가는데요. 2차도 마찬가지로 Vue를 사용해 개발한다고 합니다. 저는 리액트가 좋은데 말이죠? 아니면 최소한 IE를 배제하고 vue 3.0을 쓸 수 있도록 해주면 좋은데 말이죠

 

이 부분은 어쩔 수 없는 SI 프로젝트라 선택권이 없습니다. 그래도 모든 부분에서 득과 실이 있다고 생각하는데요. 취업하기 전 찍먹만 했던 뷰를 제 기술 스택으로 인정할 수 있게 됐습니다. 이 부분이 가장 큰 장점이라 열심히 해야겠습니다.

 

Fire Typing
열일

 

 

이제 기본을 단단히 하기 위해 다시 공부 기록용 포스팅을 이어나가도록 하겠습니다. 이전 트랜스파일러와 바벨에 대해서 포스팅했는데요. 오늘은 모듈 번들러인 웹팩에 대해 다시 공부해봤습니다.

 

 

모듈 번들러와 웹팩
https://thumbnail-maker.web.app/

모듈 번들러


리액트나 뷰는 아는데 모듈 번들러와 웹팩에 대해 잘 모르시는 분들이 많더라구요? 🤔 가장 첫 번째로 모듈 번들러에 대해 짚고 넘어가겠습니다. 

 

하나의 웹 서비스는 수많은 리소스들의 집합체인데요. JS부터 CSS, 이미지 파일 등 수 많은 리소스가 복잡하게 얽히고 설켜있습니다. 가뜩이나 프로젝트와 서비스 규모도 커지면서 리액트나 뷰를 사용해보셨다면 코드의 재사용성을 위해 컴포넌트들을 모듈 형식으로 분리하는 모듈 단위의 개발방식을 사용합니다.

 

코드를 모듈 형식으로 분리한다면 반복되는 코드도 줄 뿐더러 유지보수에도 도움이 됩니다. 개발적인 측면에서는 아주 좋지만 사용자 단에서는 어떨까요?

 

사용자가 웹 서비스에 접속하면 브라우저는 해당 페이지에 필요한  리소스(js/css/image..)를 서버로 요청하게 됩니다. 모듈 형식으로 개발된 웹 서비스라면 수 많은 모듈이 필요하므로 서버로 요청하는 횟수도 증가하게 됩니다.

 

이 처럼 네트워크 비용의 증가는 사용자가 서비스를 이용하는데 걸리는 시간도 증가되며, 네트워크 문제로 유실된 모듈이 생기면 서비스에 대한 품질과 인식도 안 좋아집니다.

 

물론 규모가 크지 않고 모듈 형식으로 코드를 작성하지 않았다면 굳이 모듈 번들러를 사용해 러닝 커브만 높이는 것은 옳지 않겠죠

 

 

https://webpack.js.org/
https://webpack.js.org

 

웹팩(Webpack)과 모듈 번들러가 무엇인지 가장 쉽게 이해할 수 있는 방법은 위 이미지를 이해하면 되는데요. 왼쪽에 수많은 리소스들을 한데 모아 통합해주는 도구를 모듈 번들러라 하고 대표적인 모듈 번들러로는 대부분 웹팩(Webpack)을 사용하고 있습니다.

 

웹팩의 메인 웹사이트를 훑어보면 스폰서들을 후원 금액별로 등급을 나누어놨습니다. 구글은 약 1억 원 정도 후원을 했네요.. ag-grid부터 에어비엔비나 코인베이스, 디스코드 등 눈에 익은 로고들이 많이 보입니다.

 

 

(최근에는 vite라는 번들러가 웹팩보다 속도도 빠르고 좋다는 평을 들었는데, 나중에 사용해보고 싶네요)

 

 

이렇게 모듈 번들러를 사용해 많은 리소스들을 통합시켜 준다면 사용자 단에서 서버로 요청하는 리소스의 개수도 줄어들면서 네트워크 비용도 감소하고 서비스 품질 향상 등 이점이 많아집니다.

 

그래서 리액트나 뷰, 앵귤러 등 모듈 단위의 개발방식을 사용하는 라이브러리에서는 번들러를 필수로 사용하고 있습니다.

 

웹팩


웹팩이 어떻게 사용되고 동작하는지 이해하기 위해 리액트를 기준으로 웹팩과 바벨 설정 등 다시 정리해보려 했지만 양이 많아질 거 같아 다음 글로 나누어 작성하려 합니다. 여기서는 웹팩에 대한 기본적인 설명만 작성하고 마무리하도록 하겠습니다.

 

 

React 18 웹팩&바벨 수동 설정하기

이번 포스팅에서는 리액트 18 버전을 기준으로 웹팩 설정을 수동으로 진행해 보겠습니다. 리액트가 18 버전으로 나온지 조금 지났는데, 저는 회사에서 Vue를 계속 쓰다 보니 리액트를 공부할 시간

juni-official.tistory.com

 

웹팩 호환성 및 최소 환경


웹팩의 호환성 및 최소 환경은 공식 문서를 보면 아래와 같이 설명되어있습니다.

 

브라우저 호완성


Webpack은 ES5가 호환되는 모든 브라우저를 지원합니다(IE8 이하는 지원되지 않습니다). Webpack은 import() 및 require.ensure()을 위한 Promise를 요구합니다. 구형 브라우저를 지원하려면 이러한 표현식을 사용하기 전에 폴리필을 로드해야 합니다.

 

환경


Webpack 5는 Node.js 버전 10.13.0 이상에서 실행됩니다.

 

 

 

ES5가 지원되는 브라우저 환경에서는 웹팩을 사용할 수 있고 구형 브라우저에서는 폴리필을 사용해야 합니다. 이전 포스팅에서 설명한 폴리필도 나왔네요.

 

 

트랜스파일러(Transpiler)와 바벨(Babel)

자바스크립트를 공부하다보면 쉽게 들을 수 있는 폴리필과 바벨에 대해서 다시 공부해보며 기록해본다. 자바스크립트는 현재까지 계속 업데이트되고 있는 언어이다. 그리고 브라우저마다 자바

juni-official.tistory.com

 

웹팩 설치


npm i -D webpack webpack-cli

 

웹팩 세부 설정


웹팩을 사용할 때에는 webpack.config.js 파일에 필요한 설정들을 직접 작성합니다. 리액트의 CRA(create-react-app)를 사용하는 경우 자동으로 웹팩 설정이 되어 있어 손수 작성할 필요가 없습니다. 아래에는 웹팩 설정 시 알아야 할 개념들입니다.

 

- Mode

 

모드는 development, production, none 세 가지 설정이 있으며, 기본 값은 production입니다. 각 모드에 따라 번들된 파일의 크기가 달라지는데요. 

 

웹팩 development 모드웹팩 production 모드웹팩 none 모드
development / production / none

좌측부터 해서 development, production, none 순서입니다. production이 제일 가벼운 것을 확인할 수 있습니다. 개발 중일 때에는 'development'를 사용하고 배포 시 'production'으로 사용.

 

// webpack.config.js

module.exports = {
  mode: 'development',
};

 

- Entry

 

엔트리에는 번들링 할 파일을 알려주면 됩니다. 리액트에서 모든 모듈의 root는./src/index.js 이므로 아래와 같이 설정해주면 됩니다. 엔트리는 여러 개의 파일을 입력할 수 있어 의존성 없는 다른 파일도 존재한다면 복수로 입력해줍니다.

 

// webpack.config.js

// Entry 축약 문법
module.exports = {
  entry: './src/index.js',
//entry: ['./src/file_1.js', './src/file_2.js'], 복수일 경우
};

//module.exports = {
//  entry: {
//    main: './src/index.js',
//  },
//};

 

- Output

 

아웃풋은 번들된 파일을 내보낼 위치와 이름 등을 지정할 때 사용됩니다. output.path와 output.filename을 설정해주면 해당 경로에 설정한 파일 이름으로 번들링되어 웹팩이 저장해줍니다. 

 

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
};

 

- Loaders

 

웹팩은 기본 자바스크립트와 JSON 파일만 이해할 수 있어 다른 유형의 파일을 번들링 할 때에는 로더를 사용해 CSS나 이미지 등 처리할 수 있습니다. 로더는 module.rules 배열에 객체 형식 개별 입력해줍니다.

 

로더는 여러 종류가 있는데요. 그중 대표적으로 자바스크립트를 처리해주는 Babel과 CSS 관련 파일을 처리해주는 stlye-loader/css-loader를 설정하는 방법입니다. 둘 다 개발 모드에서 사용할 수 있도록 설치하고 rules에 아래처럼 입력해줍니다.

 

Babel Loader

npm i -D babel-loader @babel/core @babel/preset-env
module: {
        rules: [
            {
                test: /\.js/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'] // 여러 프리셋을 설정할 수 있습니다
                    }
                }
            },
        ]
    },

 

style-loader/css-loader

npm i -D style-loader css-loader
// webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
    ],
  },
};

 

- plugins

 

프러그인은 모듈을 변환하는 데 사용할뿐더러, 번들 작업을 최적화, 리소스 관리, 환경변수 주입 등 많은 작업을 수행할 수 있습니다. 플러그인을 사용하려면 require()를 통해 플러그인을 불러오고 plugins 배열에 new 연산자로 인스턴스를 생성해 사용합니다.

 

기본적으로 사용하는 HtmlWebpackPlugin을 설정해보겠습니다. 해당 플러그인은 번들된 모들 파일을 자동으로 삽입하여 배포용 HTML 파일을 생성해줍니다.

 

HtmlWebpackPlugin 설치

npm i -D html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    plugins: [
        new HtmlWebpackPlugin(
            { 
                template: './public/index.html', // 템플릿 설정
                minify: true, // 압축 설정
            }
        ),
    ],
}

 

플러그인 종류는 여러 가지가 있는데요. 주석을 남겨주는 플러그인이나 이미지를 다룰 때 제가 좋아하는 webp 확장자로 변환해주는 플러그인도 있다고 합니다. webp 변환 플러그인은 다음 포스팅으로 리액트를 기준으로 웹팩 수동 설정 방법 포스팅에서 남겨보도록 하겠습니다.

마무리


이렇게 웹팩 설정을 마무리했습니다. 대략 아래와 같이 나왔는데요. 저는 다음 포스팅 준비로 리액트 기준으로 설정하고 설명 안 한 부분은 지워서 올렸습니다.

 

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    name: 'custom-webpack-config',
    mode: 'development', // production, development
    devtool: 'eval',
    entry: {
        app: './src/index.js',
    },
    module: {
        rules: [
            {   
                test: /\.js/, 
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },
            {
                test: /\.css$/i,
                use: ["style-loader", "css-loader"],
            },
        ]
    },
    plugins: [
    	new CleanWebpackPlugin(),
        new HtmlWebpackPlugin(
            { 
                template: './public/index.html', // 템플릿 설정
                minify: true, // 압축 설정
            }
        ),
    ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'app.js'
    },
}
npm i -D clean-webpack-plugin

 

추가로 CleanWebpackPlugin이 추가되었는데요. 번들 시 이전 번들된 결과들을 지워주는 플러그인입니다. 리액트에서는 기본적으로 사용하고 있어 추가해놨습니다.

참고자료


 

Concepts | webpack

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

webpack.js.org