본문 바로가기
코드스테이츠 42기/[TIL] Section 4

Unit3 - [React] 번들링과 웹팩과제

by 랜덤다이스 2023. 1. 18.

 

웹팩이란?

  • 현재 프론트엔드 애플리케이션 배포를 위해 가장 많이 사용하는 모듈 번들러(Module Bundler)이다.
  • 모듈 번들러란 웹 애플리케이션을 구성하는 HTML, CSS, JavaScript, image 등의 자원을 전부 각각의 모듈로 보고 이를 조합해 하나의 묶음으로 번들링(빌드)하는 도구를 의미한다.

모듈이란?

  • 모듈이란 프로그래밍 관점에서 특정 기능을 갖는 작은 코드 단위를 의미한다.
  • 웹팩에서 지칭하는 모듈은 자바스크립트 모듈에만 국한된 것이 아닐, 웹 애플리케이션을 구성하는 모든 자원을 의미.

모듈 번들링이란?


그림과 같이 웹 애플리케이션을 구성하는 몇십, 몇백개의 자원들을 하나의 파일로 병합 및 압축해주는 동작을 모듈 번들링이라고 한다.

Webpack의 필요성

  • 웹 애플리케이션의 빠른 로딩 속도와 높은 성능을 위해 필요하다.
    • 웹 페이지를 구성하는 코드의 양이 많으면(무거우면) 웹 페이지의 로딩 속도와 성능이 저하된다.
    • 일반적으로 하나의 웹사이트에 접근하는 순간부터 3초 이내에 페이지가 뜨지 않으면 이탈을 택하는 유저가 많다.
    • 로딩 속도를 개선하기 위한 노력으로 브라우저에서 서버로 요청하는 파일의 숫자를 줄이는 것이 있다.
    • 각 자원들을 일일이 서버에 요청할 필요없이 webpack을 통해서 같은 타입의 파일들은 묶어서 요청 및 응답을 받을 수 있어서 네트워크 코스트가 줄어든다.
  • 일부 브라우저에서 지원하지 않는 JavaScript ES6 문법 → ES5로 변환하는 babel-loader 사용할 수 있다.
  • 개발자가 선택하는 최선의 개발 방식으로 개발할 수 있게 지원- 웹 개발 작업 자동화 도구
  • Webpack4 버전 이상부터는 Develoment, Production 두 가지의 모드를 지원
    • Production 모드로 번들링을 진행할 경우, 코드 난독화, 압축, 최적화(Tree Shaking) 작업을 지원하기도 한다. 상용화 된 프로그램을 사용자가 느끼기에 더욱 쾌적한 환경 및 보안까지 신경쓰면서 노출시킬 수 있다.

Webpack의 핵심 컨셉 4가지

1. Entry

  • 번들링을 원하는 파일 위치(다른 모듈을 사용하고 있는 최상위 자바스크립트 파일)
  • 웹팩은 엔트리를 통해서 필요한 모듈을 로딩하고 하나의 파일을 묶는다.

2. Output

  • 번들되 결과물을 내보낼 위치

3. Loader

  • JavaScript, JSON 파일이 아닌 다른 유형의 파일 처리
  • image, font, stylesheet 등의 파일을 웹팩이 이해할 수 있는 모듈로 변환시킨다.
    • test: 변환이 필요한 파일들을 식별하기 위한 속성(필수)
    • use: 변환을 수행하는데 사용되는 로더를 가리키는 속성(필수)
    • exclude: 바벨로 컴파일하지 않을 파일이나 폴더를 지정. (반대로 include 속성을 이용해 반드시 컴파일해야 할 파일이나 폴더 지정 가능)

4. Plugin

  • 로더로 설정하기 애매한 부분 등 광범위한 작업
  • 번들된 결과물을 처리
  • bundle optimization, asset management, injection of environment

참고 : https://velog.io/@seul_/%EB%B2%88%EB%93%A4%EB%A7%81%EA%B3%BC-%EC%9B%B9%ED%8C%A9

진행할 과제 간단 소개

이번 유닛에서 웹팩을 학습하면서 진행한 웹팩을 이용한 번들링 과제를 기록해보려고 한다.

바닐라 js로 작성한 프로젝트 하나를 src 디렉토리에 복사해와서 js → html → css 순서로 번들링 진행했다. (이렇게 작은 프로젝트에 번들링이 필요한 과정일지 모르겠으나, 웹팩에 친숙해지는데는 큰 도움이 되었다.)

1. 현재 디렉토리에 npm 설치

npm init -y

  • package.json 파일 생성됨

2. webpack 설치

npm install -D webpack webpack-cli

  • -D : --save-dev package.json 파일의 devDependencies 항목에 저장(개발 단계에서만 이용)

3. Webpack 설정 파일 작성

  • 웹팩은 우선 번들링하는 원하는 파일을 확인하고(entry), 여기에 import한 라이브러리나 코드가 있으면 해당 코드를 모드 인식해서 하나의 번들(output) 안으로 압축한다.
  • webpack.config.js 파일에 entry와 output 정보를 작성한다.
const path = require('path');

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

4. js 파일 번들링 하기

npx webpack

  • src 폴더에 있는 js 파일을 번들링한다.
  • package.json 파일에 스크립트를 추가해서 번들링을 명령어를 사용할 수 있다. 이제 npm run build 로 번들링을 실행할 수 있다.
"scripts": {
    "build": "webpack",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  • 번들링 결과 output으로 지정해준 dist 폴더가 생겼고, dist/app.bundle.js 파일에 웹팩이 uglify, minify를 통해 읽기 어려운 한 줄의 코드로 바꿔놓은 것을 확인할 수 있다.

5. HTML파일 번들링하기 (plugin)

5-1. html-webpack-plugin 설치

npm i -D html-webpack-plugin

5-2. webpack.config.js 파일에 해당 플러그인을 등록

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'app.bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'src', 'index.html'),
    }),
  ],
};
  • template 옵션을 추가해서 기존에 만들어둔 파일을 이용해서 html 번들링 파일을 생성한다.

5-3. npm run build 로 번들링 한다.

5-4. dist 폴더에 index.html 파일이 생성된다.

<script defer="defer" src="app.bundle.js"></script>
  • 그리고 파일을 열어보면 위 코드가 추가 되어 있는 것을 볼 수 있다.
  • index.html 브라우저에서 실행시켜보면 스타일은 적용되지 않았지만 잘 동작하는 것을 확인할 수 있다.

6. CSS 번들링 (loader)

6-1. style-loader  css-loader 설치

npm i -D style-loader css-loader

6-2. index.js 파일에서 CSS 파일 임포트

import './style.css";
  • index.js파일을 기준으로 css파일을 함께 묶어주는 개념이기때문에 css파일과의 연결 관계도 js파일에 명시되어야 한다(는 것으로 이해했다..)

6-3. webpack.config.js 웹팩 설정 로더 등록

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'app.bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
  module : {
    rules: {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
        exclude: /node_modules/,
    }
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'src', 'index.html'),
    }),
  ],
};
  • module.rules 속성에 등록한다.
  • test 항목에 정의된 정규식에 매칭되는 파일(확장자가 .css인 파일)은 use 항목에 등록된 로더를 통해서 처리된다.
  • 로더는 css-loader가 먼저 적용되고, styled-loader가 적용된다.(순서에 주의)
  • exclude 규칙은 필수는 아니다.

6-4. npm run build 로 번들링 한다.
6-5. dist/index.html 파일을 브라우저에서 열어보면 스타일이 적용된 것을 확인 할 수 있다.

  • <header>태그 내부에 있는 style 태그에 해당 css 스타일이 적용됨 (internal 방식)

여기까지 진행하면 내 프로젝트 파일이 모두 dist 폴더 아래에 번들링된다. 아래에는 advanced 과제를 진행하면서 알게된 내용을 정리해보려고 한다.

Advanced Challenge

github page 배포

  • webpack.config.js 에서 output을 dist에서 docs로 바꿔준다.
  • 이미 번들링된 dist파일이름을 docs로 바꿨다.(깃헙 페이지 배포가 목표라면 애초에 output을 docs로 설정하고 저장할 것! )
  • 빌드를 다 마치고 git push
  • 현재 작업 중인 깃헙 리포지토리의 setting- pages에서 source 옵션을 현재 브랜치, root를 /docs 폴더로 설정하고 저장한다.

webpack-dev-server

코드 변경시마다 빌드를 다시 하고 이 결과물을 브라우저에 띄워서 확인하는 과정을 편리하게 진행할 수 있다.
실제 번들링된 결과물을 파일로 생성하는 것이 아니라, 메모리에 올려놓은채로 보여주기 때문에 빠른 속도로 변경된 코드를 개발 서버에 반영해서 보여줄 수 있다.
(create-react-app으로 개발할때 npm start로 실행해놓으면 변경 내용을 저장하면 라이브 서버로 바로바로 결과를 확인해볼 수 있는 것처럼!)

npm i -D webpack-dev-server

webpack.config.js 웹팩 설정

devServer: {
  static: {
    directory: path.resolve(__dirname, 'dist'),
  },
    port: 3001, //포트 번호는 임의로 지정한다.
},

package.json scripts에 webpack serve를 추가

"scripts": {
    "build": "webpack --mode=production",
    "start": "webpack serve --open --mode=development",
    "test": "echo \"Error: no test specified\" && exit 1"
},
  • 개발 모드에서 사용하기 때문에 mode옵션을 위와 같이 작성

npm start로 실행해놓으면, 변경되는 코드를 바로바로 반영해서(빌드된 것처럼) 보여준다.

clean-webpack-plugin

기존 빌드를 통해 생성되었지만 사용하지 않는 번들 파일을 지우고싶은 경우 사용하는 플러그인

npm i -D clean-webpack-plugin

webpack.config.js 웹팩 설정

const {CleanWebpackPlugin} = require("clean-webpack-plugin");

module.exports = {
  // 생략
  plugins: [new CleanWebpackPlugin()],
};

배포 페이지 및 전체 설정 코드

https://seul-dev.github.io/bundling-webpack-prac/

package.json

{
  "name": "bundling-webpack-prac",
  "homepage": "https://seul-dev.github.io/bundling-webpack-prac",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode=production",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist",
    "start": "webpack serve --open --mode=development",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^4.0.0",
    "css-loader": "^6.7.1",
    "gh-pages": "^4.0.0",
    "html-webpack-plugin": "^5.5.0",
    "style-loader": "^3.3.1",
    "webpack": "^5.74.0",
    "webpack-cli": "^4.10.0",
    "webpack-dev-server": "^4.9.3"
  }
}

webpack.config.js

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

module.exports = {
  entry: './src/index.js',
  output: {
    filename: 'app.bundle.js',
    path: path.resolve(__dirname, 'docs'),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'src', 'index.html'),
    }),
    new CleanWebpackPlugin(),
  ],
  devServer: {
    static: {
      directory: path.resolve(__dirname, 'docs'),
    },
    port: 3001,
  },
};

참고 : https://velog.io/@seul_/%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%9B%B9%EC%95%B1-%EB%B2%88%EB%93%A4%EB%A7%81-%ED%9B%84-%EB%B0%B0%ED%8F%AC%EC%9B%B9%ED%8C%A9-%EA%B8%B0%EC%B4%88-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC