코딩/코드스테이츠

[React] - 번들링과 웹팩

김기지 2023. 3. 20. 23:04

🌱 번들링

여러 제품이나 코드, 프로그램을 묶어서 패키지로 제공하는 행위
번들 : 사용자에게 웹 애플리케이션을 제공하기 위한 파일 묶음
  • 사용자가 더 쉽고 빠르게 프론트엔드 애플리케이션에 접근할 수 있도록 용량을 줄이거나 파일을 최소화하여 유저에게 전달하는 과정
    • 사용자가 브라우저를 열고 주소를 입력하면, 해당 주소에서 개발자가 번들링한 여러 파일을 받음
    • 이 파일을 브라우저가 실행하여 웹 애플리케이션을 제공

🌱 번들링의 필요성

HTML, CSS, JavaScript 파일을 그대로 전송할 시 생길 수 있는 문제점

  • 두 개의 .js파일에서 같은 변수를 사용하고 있는 경우 → 변수 간 충돌이 일어남
  • 딱 한 번 불러오는 프레임워크 코드가 8MB → 인터넷 속도가 느린 국가의 모바일 환경에서는 사용이 불편
  • 번들 파일 사이즈를 줄이기 위해 파일의 공백을 모두 지움 → 가독성이 너무 떨어져 코딩하기 어려움
  • 배포 코드가 너무 읽기 쉬워 개발을 할 줄 아는 사용자가 프론트엔드 애플리케이션을 임의로 조작하여 피해 발생

번들링 작업에서는 필연적으로 용량을 줄이고 파일을 통일하는 툴링 작업이 필요하다.

➡︎ 소프트웨어를 잘 만들어도 사용자에게 배포하기 위해 번들링이 꼭 필요하다.


🗂️ 웹팩

현재 프론트엔드 애플리케이션 배포를 위해 가장 많이 사용하는 번들러

🗂️ Webpack이란

여러 개의 파일을 하나의 파일로 합쳐주는 모듈 번들러
  • 모듈 번들러
    • HTML, CSS, JavaScript 등의 자원을 전부 각각의 모듈로 보고 이를 조합해 하나의 묶음으로 번들링(빌드)라는 도구

 

모듈 번들러(Module Bundler)의 등장

모던 웹으로 발전하면서 JavaScript 코드의 양이 증가

+

대규모의 의존성 트리를 가진 대형 웹 애플리케이션의 등장으로 세분화된 모듈 파일이 폭발적으로 증가

→ 모듈 단위의 파일들을 호출해 브라우저에 띄우려면

  1. 자바스크립트 언어의 특성에 따라 발생하기 쉬운 각 변수들의 스코프 문제 해결
  2. 각 자원을 호출할 때 생겨나는 네트워크 쪽의 코스트도 신경써야함

➡︎ 이러한 복잡성에 대응하기 위해 하나의 시작점(ex. React App 의 index.js)으로부터 의존성을 가지는 모듈을 모두 추적하여 하나의 결과물을 만들어내는 모듈 번들러가 등장하게 되었다.

 


웹팩에서의 모듈

 

  • HTML, CSS, JavaScript
  • .jpg나 .png같은 이미지 파일들도 전부 포함

→ 웹팩은 주요 구성 요소인 로더(loader)를 통해 다양한 파일도 번들링 가능

 


빌드와 번들링

  • 빌드
    • 개발이 완료된 앱을 배포하기 위해 하나의 폴더(directory)로 구성하여 준비하는 작업
    • React앱에서 npm run build 실행 시 React build작업이 진행되고, index.html파일에 압축되어 배포에 최적화된 상태를 제공
  • 번들링
    • 파일을 묶는 작업. 모듈간의 의존성 관계를 파악해 그룹화하는 작업
      • 파일은 의존적 관계에 있는 파일들(import, export) 그 자체 혹은 내부적으로 포함되어 있는 모듈을 의미

 


🗂️ Webpack의 필요성

웹팩이 필요한 가장 큰 이유는 웹 애플리케이션의 빠른 로딩 속도와 높은 성능을 위함

웹 페이지를 구성하는 코드의 양이 많은 것을 “무겁다”라고 표현하고, 무거울 수록 웹 페이지의 로딩 속도와 성능은 저하된다.

유저는 하나의 웹 사이트에 접근하는 순간부터 3초 이내에 웹 페이지가 뜨지 않으면 이탈하기 때문에 로딩 속도를 개선하기 위한 노력이 필요했다.

→ 브라우저에서 서버로 요청하는 파일의 숫자를 줄이자!

  • 웹팩으로 같은 타입의 파일들을 묶어 요청 및 응답을 받을 수 있다.

→ 네트워크 코스트가 획기적으로 줄어듬

 

  • webpack loader를 사용하면 일부 브라우저에서 지원하지 않는 JavaScript ES6의 문법들을 ES5로 변환해주는 babel-loader를 사용할 수 있게된다.
    • Vue의 경우 vue-loader
    • scss파일의 경우 css파일로 변환해주는 scss-loader
    → 개발자가 원하는 최선의 개발 방식을 선택해 개발할 수 있다.

 

  • Webpack 4버전 이상부터는 Development, Production 두 가지의 모드를 지원한다.
    • Production모드로 번들링을 진행하는 경우, 코드 난독화, 압축, 최적화(Tree Shacking)작업을 지원하기도함
    → 상용화된 프로그램을 사용자가 느끼기에 더욱 쾌적한 환경 및 보안까지 신경쓰면서 노출시킬 수 있다.

🗂️ 웹팩의 핵심 컨셉

📍 웹팩의 핵심 개념

웹팩 공식 문서에서는 아래 항목을 핵심 개념으로 제안하고 있다.
  • Entry
  • Output
  • Loaders
  • Plugins
  • Mode
  • Browser Compatibility
// webpack의 config 파일 예시
module.exports = {
  target: ["web", "es5"],
  entry: "./src/script.js",
  output: {
    path: path.resolve(__dirname, "docs"),
    filename: "app.bundle.js",
    clean: true
  },
  module: {
    rules: [
      {
        test: /\\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html"),
    }),
    new MiniCssExtractPlugin(),
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ]
  }
};

Target

웹팩은 다양한 환경과 target을 컴파일한다.
  • target의 기본값은 web (적용하지 않을시 기본값 적용)
  • web외에도 다양한 환경을 컴파일 할 수 있다.
    • esX를 넣으면 지정된 ECMAScript 버전으로 컴파일
module.exports = { target: ["web", "es5"], };
  • config 파일에 es5를 배열 안에 넣음→ 작성된 코드를 es5버전으로 컴파일하겠다고 지정한것임 ( 브라우저와 동일한 환경에서 config파일을 사용하기 위해)➡︎ Browser Compatibility와 연관된 속성으로 볼 수 있다.
  •  

Entry

개발자가 작성한 코드의 시작점
  • React도 index.js에서 HTML 엘리먼트 하나에 React 코드를 적용하는 것 부터 시작한다.
  • Entry 속성은 Entry point라고 한다.
    • webpack이 내부의 디펜던시 그래프를 생성하기 위해 사용해야하는 모듈
    • webpack은 entry point를 기반으로 직간접적으로 의존하는 다른 모듈과 라이브러리를 찾아낼 수 있음
    //기본 값
    module.exports = {
    	...
      entry: "./src/index.js",
    };
    
    //지정 값
    module.exports = {
    	...
      entry: "./src/script.js",
    };
    

Output

생성된 번들을 내보낼 위치와 이 파일의 이름을 지정하는 방법을 웹팩에 알려주는 역할을 한다.
  • 기본 출력 파일의 경우 ./dist/main.js 폴더로 설정
  • 생성된 기타 파일의 경우 ./dist 폴더로 설정
const path = require('path'); 
module.exports = {
	... 
    output: { path: path.resolve(__dirname, "docs"), // 절대 경로로 설정을 해야함
    filename: "app.bundle.js", clean: true 
	}, 
};
  • output.filename과 output.path 속성을 사용하여 webpack에 번들의 이름과 내보낼 위치를 알려줌
  • path 속성을 사용할 때는 path 모듈을 사용해야 함

Loader

웹팩은 기본적으로 자바스크립트와 JSON 파일만 이해한다.
loader를 사용하면 웹팩이 다른 유형의 파일을 처리하거나, 유효한 모듈로 변환해 애플리케이션에 사용하거나 디펜던시 그래프에 추가할 수 있다.
  • 상위 수준에서 loader는 웹팩 설정에 몇 가지 속성을 가진다.
    • test : 변환이 필요한 파일들을 식별하기 위한 속성. 필수 속성
    • use : 변환을 수행하는데 사용되는 로더를 가리키는 속성. 필수 속성
    • exclude : 바벨로 컴파일하지 않을 파일이나 폴더를 지정
      • 반대로 include 속성을 이용해 반드시 컴파일해야 할 파일이나 폴더 지정 가능
    module.exports = {
    	...
      module: {
        rules: [
          {
            test: /\\.css$/,
            use: [MiniCssExtractPlugin.loader, "css-loader"],
            exclude: /node_modules/,
          },
        ],
      },
    };
    
    • 속성을 넣어 규칙을 정하기 위해서는 module.rules 아래에 정의해야함
    • rules 아래에 정의할 경우 웹팩은 경고를 보냄

Plugins

번들을 최적화하거나 에셋을 관리하고, 또는 환경변수 주입 등 광범위한 작업을 수행한다.
  • 플러그인을 사용하기 위해서는
    1. require()를 통해 플러그인을 요청
    2. plugins배열에 사용하고자 하는 플러그인을 추가
  • 대부분의 플러그인은 사용자가 옵션을 통해 지정할 수 있다.

    → 다른 목적으로 플러그인을 여러 번 사용하도록 설정할 수 있기 때문에 new 연산자를 사용해 호출하여 플러그인의 인스턴스를 만들어줘야 한다.

const webpack = require('webpack');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  ...
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html"),
    }),
    new MiniCssExtractPlugin(),
  ],
};
  • html-webpack-plugin은 생성된 모든 번들을 자동으로 삽입하여 애플리케이션용 HTML 파일을 생성
  • mini-css-extract-plugin은 CSS를 별도의 파일로 추출해 CSS를 포함하는 JS 파일 당 CSS 파일을 작성해주게끔 지원

Optimization(최적화)

웹팩은 버전 4부터는 선택한 항목에 따라 최적화를 실행한다.
  • 최적화하기 위해 다양한 옵션이 지원된다.
    • minimize
      • TerserPlugin 또는 optimization.minimize에 명시된 plugins로 bundle 파일을 최소화(=압축)시키는 작업 여부를 결정
    • minimizer
      • defualt minimizer을 커스텀된 TerserPlugin 인스턴스를 제공해서 재정의
    module.exports = {
      ...
      optimization: {
        minimizer: [
          new CssMinimizerPlugin(),
        ]
      }
    };
    
    • mini-css-extract-plugin에 관련된 번들을 최소화하도록 지시하고 있다.

📍 webpack의 주요 컨셉

1.

 

  • entry 파일이 필요한 모든 것을 webpack이 모아서 번들링 해준다.
  • 번들링의 결과물이 output 경로로 산출된다.

 

📍 웹팩은 하나의 파일에 넣는 과정에서 자바스크립트의 특이점들을 극복하기 위해 복잡다단한 과정을 거친다.

더보기

+과정은 추가적으로 학습

Why webpack | webpack

 

2.

 

 

  • loader는 JavaScript, JSON이 아닌 파일을 불러오는 역할을 한다.

 

 

 

 

 

3.

 

 

  • 플러그인은 번들링 과정 중에 개발자가 원하는 다양한 작업을 할 수 있도록 도와준다.
  • html-webpack-plugin은 번들링 과정 중 html파일을 자신이 원하는 형태로 가공하여 번들에 포함할 수 있게 도와준다.

 

 

 

➰ 로더와 다르게, 플러그인은 명칭 하나로 해당 플러그인의 역할을 파악하기 애매하다.

이런 경우 사용량을 기준으로 많이 사용하는 플러그인이 왜 많이 사용되는지 먼저 찾아보는 방식으로 우선순위를 정하는게 좋다. 사용량이 높다고 원하는 플러그인인 경우가 아닐 수도 있지만, 개발 환경을 구성할 때 내가 필요한게 무엇인지를 정확하게 구분하는 것이 중요하다.


🗂️ 웹팩과 리액트

📍 리액트가 번들링이 필요한 이유

리액트가 주목받던 이유 중 하나는 프레임워크가 아닌 라이브러리라는 점이다.

리액트는 2010년대 주류였던 앵귤러의 단점을 보완할 수 있는 대체제로 생겨났다.

필요한 코드의 양이 많고, 배우는데 필요한 시간이 오래 걸리고, 번들 사이즈가 커져 성능 문제가 큰 프레임워크가 아닌 개발자의 필요에 따라 설치가 가능한 라이브러리라는 점이 리액트를 주목받게 했다.

리액트 개발진은 개발자가 어떤 기술 스택을 사용할지 미리 가정하지 않아 개발자의 자유도에 따라 기능을 추가할 수 있게 했다. 하지만 이런 특성 때문에 ‘리액트만 알아서는 개발하기가 어렵다’는 문제가 발생했다.

이런 문제를 해결하기 위해, 리액트 개발진은 create-react-app이라는 툴 체인을 개발했다. create-react-app은 리액트를 ‘간단하게’ 시작하기 위한 것으로 react-script에 사용되는 라이브러리 목록이 매우 많다.

반대로, 사용자에게 최적의 번들을 제공하기 위한 전문 프론트엔드 개발자들은 create-react-app의 거대한 라이브러리 목록을 줄이고자 직접 웹팩을 설치하여 하나씩 필요한 라이브러리 설정을 하기 시작했다.

 

➡︎ 리액트는 프론트엔드 라이브러리로서 최소한의 기능을 제공하고자 가볍게 만들어졌지만, 개발자의 다양한 니즈를 충족시키기 위해 더 많은 라이브러리를 필수적으로 사용해야만 했다. 따라서 개발자가 필요한 라이브러리를 골라서 번들링 할 수 있는 웹팩이 필요하게 되었다.

 


📍 리액트 개발에 꼭 필요한 라이브러리

  • react
    • 리액트 컴포넌트와 Hooks, 라이프 사이클에 대한 정보가 모두 들어있음
  • react-dom
    • 리액트 코드를 브라우저에 보여줄 수 있음
  • babel
    • JSX를 JavaScript로 변경하여 entry에서 불러올 수 있게 만듬
    • 브라우저에서 JavaScript는 읽을 수 있지만 JSX는 읽을 수 없음
    • → babel이 jsx를 js로 변경해주어 번들링
  • css-loader
    • import로 CSS를 적용하기 위해 필요

📍 리액트 개발에 도움이 되는 라이브러리

  • react-hot-loader
    • webpack-dev-server처럼 저장할 때 마다 변경사항을 개발 환경에 적용해주는 라이브러리
    • 리액트의 상태를 유지시켜줌
  • eslint
    • JavaScript로 개발 시 자주 접하는 에러를 방지하기 위한 린터
    • eslint에 많은 config와 plugin이 있는데, 이를 잘 조합하면 리액트에서 자주 접하는 에러를 미리 발견하는데 도움이 됨
  • prettier
    • JavaScript로 개발 시 통일성 있게 코드 형식을 맞출 수 있게 도와주는 툴
    • eslint와 조합해서 통일된 코드 형식까지 강요할 수 있음
728x90