번들링과 웹팩

1Hoit·2023년 3월 21일
0

자바스크립트

목록 보기
25/25

들어가기전...

  • 웹을 개발하다보면 다양한 확장자의 파일을 만들게 된다.
    이렇게 다양한 소스는 웹 어플리케이션을 무겁게 만든다.
    통신이 있을 때마다 이 소스들을 로딩하는 작업은 고비용이다.
    만약 많은 JS 패키지를 사용하다보면 예상하지 못한 충돌로 인해 어플리케이션이 깨지게 될 수도 있다(같은 이름을 변수를 사용하는 등).
    이를 해결하기 위해 등장한 도구가 Bundler이다.
    bundle은 묶는다는 뜻이다.
    여러개의 파일을 묶어주는 어떠한 정리 방법이다.
    구체적인 기술로는 WebPack, Broserify, Parcel이 있다.

번들링?

여러 제품이나, 코드, 프로그램을 나누어서 패키지로 제공하는 행위를 의미한다.

  • 프론트 엔드에서 번들이란?
    사용자에게 웹 애플리케이션을 제공하기 위한 파일 묶음이다

번들링의 필요성

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

    위와 같은 이유를 위해
    번들링 작업에서는 필연적으로 용량을 줄이고 파일을 통일하는 툴링 작업이 필요하다.
    즉, 소프트웨어를 잘 만들어도 사용자에게 배포하기 위해 번들링이 꼭 필요하다.

Webpack

여러 개의 파일을 하나의 파일로 합쳐주는 모듈 번들러이다.

  • 모듈 번들러란 HTML, CSS, JavaScript 등의 자원을 전부 각각의 모듈로 보고 이를 조합해 하나의 묶음으로 번들링(빌드)하는 도구이다
  • Webpack에서의 모듈은 JavaScript 모듈과 HTML, CSS, 혹은 .jpg나 .png 같은 이미지 파일들도 전부 포함한 포괄적인 개념이다.
  • 성능을 향상시키기 위해 필요하다면 다시 분리할 수도 있다.
  • Webpack은 현재 프론트엔드 애플리케이션 배포를 위해서 가장 많이 사용하는 번들러이며 다양한 다른 번들러 들도 있다.
    (WebPack을 둘러싼 방대한 생태계 덕분에 다양한 확장 기능 등이 있기 떄문에 많은 작업들을 자동화 하기 편하다.)

빌드와 번들링

  • 빌드는 개발이 완료된 앱을 배포하기 위해 하나의 폴더(directory)로 구성하여 준비하는 작업이다
    • React 앱 같은 경우 npm run build 커맨드를 통해 React build 작업이 진행되고, index.html 파일에 압축되어 배포에 최적화된 상태를 제공한다.

빌드와 번들링의 차이

먼저 빌드과정에 번들링은 포함된다. (빌드 > 번들링)

  • 빌드 : 개발자가 작성한 코드를 웹서버(인터넷)에 실행 가능한 형태로 제공한다.
  • 번들링 : 단순히 여러개의 소스 코드를 1개의 파일로 결합하는 과정

Webpack의 필요성

웹 애플리케이션의 빠른 로딩 속도와 높은 성능을 위해서다.

  • 웹팩 사용시 얻을 수 있는 이점은 리팩토링이다.
    구동되는 방법은 그대로 유지하면서 내부의 코드를 효율적으로 바꿀 수 있다.
    여러개의 파일을 하나로 묶는 번들링 기능과 더불어 구형 브라우저에서도 사용할 수 있게 만들어 준다.
  • 참고로 일반적으로 유저는 하나의 웹사이트에 접근하는 순간부터 3초 이내에 웹페이지가 뜨지 않으면 굉장히 많은 수가 더는 기다리지 않고 이탈을 선택하기 때문에 빠른 로딩 속도가 필요하다.
  • 상용화 된 프로그램을 사용자가 느끼기에 더욱 쾌적한 환경을 제공하며 보안까지 신경쓰면서 노출시킬 수 있다는 점에서도 Webpack은 필요하다.
  • Webpack이 없다면 각 자원들을 일일히 서버에 요청해 얻어와야 하지만, Webpack이 있다면 같은 타입의 파일들은 묶어서 요청 및 응답을 받을 수 있기 때문에 네트워크 비용이 획기적으로 줄어든다.
  • Webpack loader를 사용하면 일부 브라우저에서 지원하지 않는 JavaScript ES6의 문법들을 ES5로 번환해주는 babel-loader를 사용할 수 있다.
    Vue인 경우는 vue-loader를, scss 파일 같은 경우는 css 파일로 변환해주는 scss-loader 등의 loader도 사용할 수 있기 때문에 개발자는 본인이 원하는 최선의 개발 방식을 선택해 개발할 수도와준다.
  • ebpack4 버전 이상부터는 Develoment, Production 두 가지의 모드를 지원하고 여기서 Production 모드로 번들링을 진행할 경우, 코드 난독화, 압축, 최적화(Tree Shaking) 작업을 지원해준다.

웹팩의 핵심 개념

웹팩 공식문서에서는 핵심 개념을 제안하고 있다.
웹팩 공식 홈페이지의 컨셉

  • 참고로 웹팩은 JavaScript로 된 모듈만 번들링을 한다.
    (Webpack은 기본적으로 JavaScript와 JSON 파일만 이해한다.)

    그렇기 때문에 JSX나 TypeScript 와 같이 JS를 확장한 문법은 혼자서 변환을 못하기 때문에 Babel과 같은 도구를 사용해 변환을 시켜줘야한다.

    참고로 babel은 웹팩에서 사용되는 로더 중 하나로 ES6 문법으로 작성된 코드를 ES5 문법으로 변환시켜준다(트랜스 파일러임).
    즉 이를 통해 구형브라우저에서도 동작할 수 있도록 코드를 바꿔주는 로더다. (CRA로 리액트앱생성시 자동설치된다.)
    npm i -D bable-loader @babel/core @babel/preset-env @babel/preset-react

    • babel-core : 바벨을 이용해 코드를 변환하는데 필요한 기능을 제공(트랜스 파일러 역할을 함)
    • @babel/preset-env : 언어를 변환시 특정한 변환 규칙들이 있는 것을 모은것...

그래서 아래와 같이 웹팩의 config 파일의 설정이 필요하다.

  • Entry
  • Output
  • Loaders
  • Plugins
  • Mode
  • Browser Compatibility

웹팩의 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: 코드가 실행될 플랫폼을 지정,
    위 경우 웹 플랫폼을 대상으로하며 ES5 JavaScript로 컴파일

  • entry: 응용 프로그램의 진입점을 지정,
    위 경우 src/script.js 파일

  • output: 빌드된 파일의 출력 경로와 파일 이름을 정의,
    위 경우 app.bundle.js 파일을 docs 폴더에 생성
    clean 옵션은 이전에 빌드된 파일을 자동으로 삭제

  • module: 사용자 지정 모듈을 정의,
    위 경우 .css 확장자를 갖는 파일에 대해 css-loaderMiniCssExtractPlugin.loader를 사용

  • plugins: 추가적인 기능을 제공하는 플러그인을 설정,
    위 경우 HtmlWebpackPluginMiniCssExtractPlugin을 사용. HtmlWebpackPlugin은 HTML 파일을 빌드된 JS 파일에 링크하는 index.html 템플릿 파일을 생성. MiniCssExtractPlugin은 CSS 파일을 별도의 파일로 추출

  • optimization: 웹팩이 최적화할 옵션을 설정, 이 경우 CssMinimizerPlugin을 사용하여 CSS 파일을 압축

웹팩의 config파일 설정 상세 설명

Mode

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

mode 옵션을 사용하면 webpack에 내장된 최적화 기능을 사용할 수 있다.
기본값은 production 이다

  • development: DefinePlugin의 process.env.NODE_ENV를 development로 설정한다.
    모듈과 청크에 유용한 이름을 사용할 수 있다.
  • production: DefinePlugin의 process.env.NODE_ENV를 production으로 설정한다. (배포를 위함, 가장 코드가 압축됨)
    모듈과 청크, FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, TerserPlugin 등에 대해 결정적 망글이름(mangled name)을 사용할 수 있다
  • none : 기본 최적화 옵션에서 제외

Target

module.exports = {
  target: ["web", "es5"],

Webpack은 다양한 환경과 target을 컴파일한다
target의 기본값은 web이다.
만약 esX를 넣으면 지정된 ECMAScript 버전으로 컴파일할 수 있다.

  • 위 내용을 해석한다면 브라우저와 동일한 환경에서 사용하기위해 컴파일 하며 작성된 코드를 es5 버전으로 컴파일한다는 뜻이다

Entry(엔트리)

//기본 값
module.exports = {
	...
  entry: "./src/index.js",
};

//지정 값
module.exports = {
	...
  entry: "./src/script.js",
};

프론트엔드 개발자가 작성한 코드의 “시작점"이다.
기본 값은 ./src/index.js
React도 index.js에서 HTML 엘리먼트 하나에 React 코드를 적용하는 것 부터 시작한다.
webpack이 내부의 디펜던시 그래프를 생성하기 위해 사용해야 하는 모듈이다.
Webpack은 이 Entry point를 기반으로 직간접적으로 의존하는 다른 모듈과 라이브러리를 찾아낼 수 있다.

Output(출력)

const path = require('path');

module.exports = {
	...
  output: {
    path: path.resolve(__dirname, "docs"), // 절대 경로로 설정을 해야 합니다.
    filename: "app.bundle.js",
    clean: true
  },
};

Output 속성은 생성된 번들을 내보낼 위치와 이 파일의 이름을 지정하는 방법을 webpack에 알려준다.
기본 출력 파일의 경우에는 ./dist/main.js로 ,
생성된 기타 파일의 경우에는 ./dist 폴더로 설정된다.
위의 예제에서 output.filenameoutput.path 속성을 사용하여 webpack에 번들의 이름과 내보낼 위치를 나타냈으며
path 속성을 사용할 때는 path 모듈을 사용해야만 합니다.
output.clean:true 이므로 번들링 할 때 마다 output 디렉토리의 이전 파일이 삭제된다.
filename:'[name].[hash].js'와 같이 작성한다면
output이 동적으로 변해 파일이름이 달라진다.
[name]의 기본은 main이 된다.

Loader(로더)

module.exports = {
	...
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"], //style-loader 대신 CSS minify를 위한 로더를 쓰자
        exclude: /node_modules/,
      },
    ],
  },
};

npm i -D css-loader style-loader로 설치 후 사용가능
Webpack은 기본적으로 JavaScript와 JSON 파일만 이해하지만 loader를 사용하면 Webpack이 다른 유형의 파일을 처리하거나, 그들을 유효한 모듈로 변환해 애플리케이션에 사용하거나 디펜던시 그래프에 추가할 수 있다.
즉, loader는 JavaScript, JSON이 아닌 파일을 불러오는 역할을 한다.

상위 수준에서 loader는 webpack 설정에 몇 가지 속성을 가진다.

  • test(필수): 변환이 필요한 파일들을 식별하기 위한 속성
  • use(필수): 변환을 수행하는데 사용되는 로더를 가리키는 속성
  • exclude: 바벨로 컴파일하지 않을 파일이나 폴더를 지정. (반대로 include 속성을 이용해 반드시 컴파일해야 할 파일이나 폴더 지정 가능)

이런 속성을 넣어 규칙을 정하기 위해서는 module.rules 아래에 정의해야 한다 그냥 rules 아래에 정의하면 webpack은 경고날림

Plugins(플러그인)

Plugins를 사용하면 번들을 최적화하거나 에셋을 관리하고, 또는 환경변수 주입 등의 광범위한 작업 수행
npm i -D html-webpack-plugin로 설치후 require()로 불러와야 사용가능 (로더랑 달리 require 필요)

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(),
  ],
};

플러그인을 사용하기 위해서는 require()를 통해 플러그인을 먼저 요청해야 하고 plugins 배열에 사용하고자 하는 플러그인을 추가해야 한다.
대부분의 플러그인은 사용자가 옵션을 통해 지정할 수 있으며 다른 목적으로 플러그인을 여러 번 사용하도록 설정할 수 있기 때문에 new 연산자를 사용해 호출하여 플러그인의 인스턴스를 만들어줘야 한다.

위의 예제에서 html-webpack-plugin 은 번들링 과정 중 html 파일을 자신이 원하는 형태로 가공하여 번들에 포함할 수 있게 돕는다.

mini-css-extract-plugin은 CSS를 별도의 파일로 추출해 CSS를 포함하는 JS 파일 당 CSS 파일을 작성해주도록 지원한다.

Optimization(최적화)

Webpack은 버전 4부터는 선택한 항목에 따라 최적화를 실행

module.exports = {
  ...
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ]
  }
};

최적화하기 위해 다양한 옵션이 지원이 되는데, 대표적으로 minimizeminimizer 등을 사용한다.

  • minimize : TerserPlugin 또는 optimization.minimize에 명시된 plugins로 bundle 파일을 최소화(=압축)시키는 작업 여부를 결정
  • minimizer : defualt minimizer을 커스텀된 TerserPlugin 인스턴스를 제공해서 재정의
    위의 예제에서는 mini-css-extract-plugin 에 관련된 번들을 최소화하도록 한다.

추가적으로 config 파일에서 설정할 수 있는 것들도 있다.

개발용 서버

npm i --save-dev webpack-dev-server 로 설치후

//webpack.config.js
entry:....,
devServer:{ //추가  
static:'./docs' //npm script 등 했을 때 개발 서버를 띄워주며 최적화가 필요함
},
...
optimization:{
  minimizer:[
  	new CsMinimizerPlugin()
  ],
    runtimeChunk:'single' // 최적화 추가
}

위와 같이 웹팩 config파일을 작성후
package.json 의 script에
"dev-server":"webpack serve --open"작성하면
$ npm run dev-server로 내 로컬 서버에서 열 수 있게 된다.

리액트 npm run start를 위한 설정

npm i react-scripts를 통해 설치 후
package.json 의 script에
"start":"react-scripts start"작성하면
$ npm run start가능하며 추가적인 submit 등과 같은 것도 할 수 있다..


profile
프론트엔드 개발자를 꿈꾸는 원호잇!

0개의 댓글