번들링과 Webpack

moontag·2022년 7월 25일
4

Webpack

목록 보기
1/3
post-thumbnail

like 치토스 번들...



번들링 사용되기 전 문제점

  • 서로다른 두 개 파일에서 같은 변수/함수 사용 시, 충돌 발생
  • 네트워크 부하
    한번 불러오는 프레임워크 코드가 8MB라, 인터넷 속도가 느린 국가의 사용자가 불편함
  • import / export가 구형 웹브라우저에서 동작 안함
  • 배포 코드가 읽기 쉬운 경우, 사용자가 프론트엔드 애플리케이션을 임의로 조작하는 피해가 발생

번들링(Bundling)

기능별로 모듈화한 JS파일들을 묶어준다는 뜻.

Bundler

: 파일들을 묶어주는 도구

  • Webpack, RequireJS, Browserify, Rollup, Parcel 등






Webpack

여러 개 파일(html,css,js,jpg,pnp 등)을 하나로 묶는 모듈 번들러



모듈번들러 등장배경

  • 대형 작업으로 인해 JS파일이 증가하면서 각 변수들의 스코프 문제, 각 자원(html,css,js 등)을 호출할 때 생기는 네트워크 쪽 코스트 문제.
  • 이에 대한 대응방안으로 시작점(ex. React 앱의 index.js)으로부터 의존성을 가지는 모듈을 모두 추적해서 하나로 만드는 모듈 번들러가 등장.



필요성

  • 웹 앱의 빠른 로딩 속도, 높은 성능

  • 웹팩으로 같은 타입의 파일들을 한 대 묶어서 요청/응답 받으므로 네트워크 코스트 절감

  • Webpack loader를 사용하면 ES6의 문법들을 ES5로 번환해주는 babel-loader를 사용할 수 있음.
    Vue의 경우 vue-loader를,
    scss 경우는 css 파일로 변환해주는 scss-loader 등의 loader도 사용할 수 있기에 각자가 선택해 개발할 수 있음

  • Webpack4 버전 이상부터 Develoment, Production 두 가지 모드를 지원.
    Production 모드의 경우, 코드 난독화, 압축, 최적화(Tree Shaking) 작업 지원



빌드

개발 완료된 앱을 배포하기 위해 하나의 폴더로 구성하는 작업

  • 예) React앱 - npm run build실행하면 React build진행되고 index.html에 압축되어 배포 최적화 상태 구축해준다

번들링

  • 파일(import, export나 내부에 있는 모듈 등)을 묶는 작업
  • 모듈 간 의존성 관계를 파악하여 그룹화하는 작업



핵심 개념

  • 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

: 다양한 환경 컴파일 가능하게 함.

  • 기본값: web
  • "es5" 넣으면 지정된 ECMAScript 5버전으로 컴파일함
  • Browser Compatibility 호환성과 연관됨.

Entry

: 시작점.

  • entry 파일이 모든 것을 모아서 번들링함
  • webpack이 내부의 디펜던시 그래프를 생성하기 위해 사용해야 하는 모듈
  • 기본값 ./src/index.js
    //기본 값
      entry: "./src/index.js",
    //지정 값
      entry: "./src/script.js",

Output

번들 내보낼 위치path, 번들 파일명filename 지정방법을 웹팩에 알려줌

  • 기본 출력 파일: ./dist/main.js
  • 생성된 기타 파일: ./dist 폴더
  • path : 번들링된 결과물이 담길 주소
  • path 속성 사용 시 path 모듈을 사용해야만 함
const path = require('path');

module.exports = {
	...
  output: {
    path: path.resolve(__dirname, "docs"), // 절대 경로로 설정 해야 한다. 
    filename: "app.bundle.js",
    clean: true // 번들링할때마다 dist폴더 정리하기
  },
};

Loaders

: JavaScript, JSON이 아닌 파일을 불러오는 역할
웹팩은 기본적으로 JS, JSON파일만 이해한다.
그러나 Loaders 사용 시, 웹팩이 다른 유형 파일을 처리하거나, 유효한 모듈로 변환해 앱에 사용하거나 dependency 그래프에 추가할 수 있음

  • test(필수) : 변환이 필요한 파일들을 식별하기 위한 속성
  • use(필수) : 변환을 수행하는데 사용되는 로더를 가리키는 속성
  • exclude : 바벨로 컴파일 안할 파일/폴더를 지정.
    (include 속성 : 반드시 컴파일해야 할 파일/폴더 지정 가능)
  • module.rules 아래에 정의해야 한다. 그냥 rules 아래에 정의하면 webpack은 경고한다.
module.exports = {
	...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
        exclude: /node_modules/,
      },
    ],
  },
};

Plugins

번들 최적화, 에셋 관리, 환경변수 주입 등 광범위한 작업 수행 가능

  • require()로 플러그인 먼저 요청
  • plugins 배열에 사용하고자 하는 플러그인을 추가
  • 다른 목적으로 플러그인을 재사용하도록 설정할 수 있기 때문에 new 연산자를 사용해 호출하여 플러그인의 인스턴스 생성
  • html-webpack-plugin
    : 생성된 모든 번들을 자동 삽입하여 애플리케이션용 HTML 파일을 생성
  • mini-css-extract-plugin
    : CSS를 별도의 파일로 추출해 CSS를 포함하는 JS 파일 당 CSS 파일을 작성해주게끔 지원
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(),
  ],
};

Optimization 최적화

웹팩 버전4부터 선택항목에 따른 최적화 가능

  • minimize : TerserPlugin 또는 optimization.minimize에 명시된 plugins로 bundle 파일을 최소화(=압축)시키는 작업 여부를 결정
  • minimizer : defualt minimizer을 커스텀된 TerserPlugin 인스턴스를 제공해서 재정의할 수 있다.
  • 밑에서는 mini-css-extract-plugin 관련 번들을 최소화하도록 지시.
module.exports = {
  ...
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ]
  }
};












튜토리얼

  • 파일생성
cd ~/Desktop
mkdir fe-sprint-webpack-tutorial
cd fe-sprint-webpack-tutorial

npm init

-> package.json파일 생성됨

npm init -y
//package.json
{
  "name": "fe-sprint-webpack-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": ""
}
  • src/index.js 파일 생성하고,
    매개변수를 console.log 하는 간단한 함수 생성
// src/index.js
const shout = (...sentences) => console.log(...sentences);



웹팩 설치

webpack은 프로젝트를 번들링하기 위한 라이브러리이긴 하지만,
실제 프로젝트에 사용하지 않으므로 devDependency 옵션 설정

npm install -D webpack webpack-cli

webpack.config.js 생성 후 작성

최근 webpack은 설정파일 없이도 작동되게 업데이트됐지만,
webpack 설정을 다룰 줄 알아야 다양한 외부 리소스를 사용하기 편하다.

const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"), // './dist'의 절대 경로를 리턴합니다.
    filename: "app.bundle.js",
  },
};

번들링하기

npx webpack

-> dist 폴더 안 app.bundel.js에 최소화된 코드로 생성되어 있음

package.json에 npm run build 설정

//package.json
{
  "name": "fe-sprint-webpack-tutorial",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack",  // 추가
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.73.0",
    "webpack-cli": "^4.10.0"
  }
}



  • 사실 create-react-app도 webpack을 사용

  • Node.js에서만 작동할 법한 코드를 모든 브라우저에서 잘 작동할 수 있도록 번들링을 해주었기 때문에 잘 작동했던 것이죠. index.html 파일을 dist 디렉터리로 옮겨서 번들 파일과 연결



로더로 css 번들에 추가하기

css-loader : CSS를 JS파일 내에서 불러올 수 있다,
style-loader : 불러온 CSS를 style 요소 내에 담아준다.

  • style 요소 자동 생성 후 작성한 CSS를 넣는 방식

1. css-loader, style-loader 설치

npm i -D css-loader style-loader

2. webpack.config.js 수정 후 npm run build

// webpack.config.js
const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "app.bundle.js",
  },
  // 여기부터 추가
  module: {
    rules: [
      {
				// 파일명이 .css로 끝나는 모든 파일에 적용
        test: /\.css$/,
				// 배열 마지막 요소부터 오른쪽에서 왼쪽 순으로 적용
				// 먼저 css-loader가 적용되고, styled-loader가 적용되어야 한다.
				// 순서 주의!
        use: ["style-loader", "css-loader"],
				// loader가 node_modules 안의 있는 내용도 처리하기 때문에
				// node_modules는 제외해야 합니다
        exclude: /node_modules/,
      },
    ],
  },
};
  • VS Code의 Format Document 기능(alt + shift + F)



html파일도 번들에 추가하기

1. html-webpack-plugin 설치

npm i -D html-webpack-plugin

2. webpack.config.js에 플러그인 적용 후 npm run build

-> 하면 dist에 index.html 파일 생성됨

const path = require("path");
const HtmlWebpackPlugin = require('html-webpack-plugin') // 추가

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "app.bundle.js",
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
        exclude: /node_modules/,
      },
    ],
  },
  // 여기부터 추가
  plugins: [new HtmlWebpackPlugin({
    template: path.resolve(__dirname, "src", "index.html")
  })]
};
  • html-webpack-plugin이 자동으로 index.html에
    <script defer="defer" src="app.bundle.js"></script> 스크립트 요소를 추가해줌





github page 배포

  1. github page 설치
npm install gh-pages --save-dev
  1. package.json에 추가
// package.json
"build": "webpack --mode=production",
    "predeploy": "npm run build",
    "deploy": "gh-pages -d dist"
  1. webpack.config.js 생성 후 작성
// 자동으로 script가 삽입되도록 하기위해서 설정 
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
  // 진입점 생성 => 진입점은 app.js
  entry: './src/app.js',
  // 출력되는 파일이름은 bundle.js 경로는 path.resolve(__dirname, 'dist')
  output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') },
  // module은 style-loader와 css-loader를 적용한다.
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },
  devServer: {
    contentBase: __dirname + '/dist/',
    host: 'localhost',
    port: 3000,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './index.html',
    }),
  ],
};
  • dist폴더명 => docs로 변경, output path에서도 dist => docs로 변경
  1. github 홈페이지 -> 현재 작업중인 레포지토리 settings -> options -> github pages를 클릭

  2. 배포할때는 npm run deploy



Mode 설정

  • 참고
  • package.json 모드에 맞게 변경
// ex) production 모드로 설정
 "build": "webpack --config webpack.config.prod.js",
  • webpack-merge로 기본(base)에 모드(dev, prod) 추가하기
npm install webpack-merge

1. development mode

  • webpack.config.dev.js 생성후 작성

      //webpack.config.dev.js
      const { merge } = require('webpack-merge')
      const baseConfig = require('./webpack.config.base')
    
      module.exports = merge(baseConfig, {
        mode: 'development',
        devServer: {
          port: 3001
        }
      })

2. production mode (기본값)

  • webpack.config.prod.js 생성후 작성

    //webpack.config.prod.js
    const { merge } = require('webpack-merge')
    const baseConfig = require('./webpack.config.base')
    
    module.exports = merge(baseConfig, {
      mode: 'production'
    })

3. config file을 모드에 맞게 나눠보기

var config = {
  entry: './app.js',
  //...
};

module.exports = (env, argv) => {
  if (argv.mode === 'development') {
    config.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    //...
  }

  return config;
};



Output 관리

  • clean: true, : 번들링 할 때 마다 dist 디렉터리를 정리하기 (참고)
output: {
     filename: '[name].bundle.js',
     path: path.resolve(__dirname, 'dist'),
    clean: true, // 추가
   },
  • "[name].bundle.js", : 번들파일명이 지정명이 아니라, 늘 동적으로 변하도록 생성하기 (참고)
filename: "[name].bundle.js",



Asset 관리

npm install --save-dev mini-css-extract-plugin
npm install css-minimizer-webpack-plugin --save-dev
  • webpack.config.base.js
//webpack.config.base.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  // 추가
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin"); // 추가

module.exports = {
  target: ["web", "es5"],
  entry: "./src/script.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    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(),
    ],
  },
};



개발용 서버

webpack-dev-server : 빠른 실시간 리로드 기능을 갖춘 개발 서버 (라이브 서버와 비슷)

  • 설치
npm install --save-dev webpack-dev-server
  • package.json 에 dev 추가
//package.json
 "dev": "webpack-dev-server --open --config webpack.config.dev.js"
  • webpack.config.dev.js에 devServer 추가
// webpack.config.dev.js
const { merge } = require('webpack-merge')
const baseConfig = require('./webpack.config.base')

module.exports = merge(baseConfig, {
  mode: 'development',
  devServer: {         // 추가
    port: 3001
  }
})



브라우저 호환성

ES6를 지원하지 않는 브라우저에서 실행 가능하게 target 속성을 활용합니다.

module.exports = {
  // ...
  target: ['web', 'es6'],
};



babel-loader 사용

npm install --save-dev babel-loader @babel/core @babel/cli @babel/preset-env
  1. babel-loader 설치
    웹팩이 모듈을 번들링할 때 Babel을 사용하여 ES6+를 ES5 코드로 트랜스파일링하도록 하는 로더
  • webpack.config.json 수정
    module: {
            rules: [
                {
                    test : /\.js$/,
                    exclude: /node_modules/,
                    use : "babel-loader"  // 추가
                },
                {
                    test : /\.css$/,
                    use : ["style-loader", "css-loader"]
                }            
            ],
        },
  1. @babel/core : babel의 핵심기능을 포함해서 반드시 설치해야 함
  2. @babel/cli : 터미널에서 바벨명령어 사용가능하도록 CLI 제공
  3. @babel/preset-react : 리액트(JSX)를 js로 인식가능
  4. @babel/preset-env : es6, es7 버전을 지정안해도 babel이 자동 탐지. 바벨프리셋이라고도 부름. 설정도 해줘야 함
  • 전체 설정 파일인 babel.config.js / babel.config.json 파일생성해 설정하는 방법(바벨 7버전부터 생김)
    • 최상위에 .babelrc 생성
      {
        "presets": [
          "@babel/preset-env",
          "@babel/preset-react",  // 설치 시 추가
        ]
      }
  • 지역 설정 파일인 .babelrc 파일과 package.json 에 babel key를 넣어서 설정하는 방법

참고

[VSCode] 웹팩(webpack)과 바벨(babel) 설정하기(3) - 바벨 기본 설정
Webpack | PoiemaWeb

https://phsun102.tistory.com/43

https://snupi.tistory.com/197?category=907277

profile
터벅터벅 나의 개발 일상

0개의 댓글