Webpack

yeong·2022년 7월 1일
0

javascript

목록 보기
4/5

webpack에 대해 정리를 해보려고한다.
웹팩이 빌드 툴로서 파일들을 합쳐주고 최적화 해준다는것 정도만 알고 있었고 webpack의 원리에 대해 알아볼 기회가 없었다.

이번에 vanilajs로 만든 프로젝트를 번들링해볼 겸 webpack을 정리하고 공부해보려고 한다.
정리는 여기를 참고하여서 진행하였다.

웹팩을 왜 배워야할까?

웹팩에 대해 잘 알지 못해도 개발은 가능하다. 그러나 성능에 대해 고민을 시작하게 된다면 웹팩을 피해갈 수 없다.
사실 작은 프로젝트에서는 웹팩으로 파일을 합쳐주는 과정(번들링)도 최적화의 필요성도 잘 못느낄 수 있다. 그러나 애플리케이션의 규모가 커질 수록 빌드툴을 이용한 번들링은 필수사항이 된다.

배워보자

웹팩의 필요성을 알았다면 이제 실전 예제를 통해 웹팩에 대해 정리해보자.
만약 기본용어가 헷갈릴때는 여기를 참조하자.

1. 프로젝트 초기화 및 패키지 설치

웹팩을 시작하기 위해서는 npm 프로젝트를 초기화해주어야한다

npm init -y

여기서 npm이란 무엇인지 잠깐 정리하자면

npm이란
node package manager의 약자로 node 모듈들을 패키지로 관리하기 위한 패키지 매니저이자 node.js를 위한 오픈소스 생태계이다

좀 더 정리가 필요하다면 여기를 참고.

프로젝트가 초기화 되었다면 webpack 패키지를 설치한다.

npm install --save-dev webpack webpack-cli webpack-dev-server

이제 package.json도 생성이고 되고 방금 설치한 webpack package의 의존성이 package.json에 추가되었을 것이다.

dev라는 명령어로 개발모드에서 웹팩을 실행하기 위해 script 필드에 "dev" 를 추가해주자.

"scripts": {
    "dev": "webpack --mode development"
    		...
  },

기본적으로 package.json이 생성되면 main이 index.js로 되어있는것을 볼 수 있다. 이는 패키지의 기본 export가 index.js임을 의미한다. 우리는 아직 index.js이 없으므로 src 폴더와 함께 index.js를 생성하자.

웹팩을 설정하기 전에!

이제 설정을 작성해야하는데 그 전에 웹팩의 중요한 요소들에 대해 알아야한다. 정리는 여기를 참조하였다.

  1. 엔트리(Entry)
  • 번들링을 시작하기 위한 진입점이다. 웹팩은 특정 범위에 있는 파일들 중 의존적인 모듈들을 모두 찾아내 번들링하는데 이때 의존 관계로 생기는 구조를 디펜던시 그래프라고한다 즉 재귀적으로 연결된 모든 모듈들이 번들링의 대상이 된다. entry에 지정된 js파일은 index.html에 삽입되는 대상이 된다(main js파일이 된다). entry는 여러개일 수도 있다.(번들된 파일이 꼭 하나인것은 아니다!)
  1. 아웃풋(Output)
  • 하나로 묶은 결과물을 저장할 위치이다.
    파일명은 별도로 지정해주거나 미지정시 entry에서 결정된 이름이 유지된다.
  1. 로더(Loader)
  • 웹팩은 모듈, 즉 자바스크립트만 읽을 수 있다. 그러므로 js가 아닌 html, css ...등의 파일들을 모듈로 변환이 필요한데 이 때 사용되는것이 로더이다. 로더는 다른 확장자를 가진 파일들을 모듈화하기 위한 도구라고 볼 수 있다.
  1. 플러그인
  • 플러그인은 번들된 결과물을 처리하는 역할을 한다.
    로더가 파일을 처리했다면 플러그인은 그 결과물에 추가적인 작업을 진행한다. 예를들어 모듈화된 HTML파일에 번들된 스크립트를 추가하는 일을 할 수 있다.

이제 웹팩을 설정해보자.

2. 웹팩 설정하고 실행하기

1) 설정파일 생성

웹팩을 설정하기 위한 내용들을 입력할 파일이 필요하다. webpack.config.js를 생성하자.

2) 엔트리 포인트, 아웃풋 설정하기

default 옵션과 다른 엔트리포인트 아웃풋을 설정할 수 있다.
엔트리 포인트의 default는 src/index.js
아웃풋의 default 위치는 dist폴더이다.

3) 플러그인 설정하기

필요한 플러그인이 있다면 설정파일에 추가해주어야한다.
해당 문서내에서는 HTML파일을 읽고 해당파일에 번들을 삽입해주는 플러그인 html-webpack-plugin의 예시를 소개하였다.

4) loader 적용하기

위에서 로더란 webpack이 js외 다른 파일들을 모듈로 만들기 위한 도구라고 하였다.
css파일을 모듈로 만들기 위해서는 css로더들을 설치하고 로더 설정 방법에 따라 작성하면 된다. 아래는 표준 예시이다.

4) 실행하기

서버를 실행하면 우리가 생성한 html파일이 열리면서 적용한 플러그인, loader들을 확인할 수 있다.
또한 html에 번들링된 스크립트 태그가 추가된것을 볼 수 있다. 해당 스크립트 태그를 살피면 속성이 defer로 지정되었음을 볼 수 있는데 모듈의 default 속성이 defer이기 때문이다. 즉 가장 마지막에 실행된다.
한가지 더 알아야할 것은, 우리는 모듈을 모아 스크립트를 추가한것인데, type이 module로 지정되지 않았는데 이는 웹팩이 번들링을 한 후 엔트리, 즉 메인 js파일에 의존 파일들이 모두 번들링되었다면 해당 파일만을 일반 스크립트로 호출하기 때문이다.

module.exports = {
...
  module: {
      rules: [
        {
          test: /\.파일확장자$/,
          use: ["로더2", "로더1"],
        },
      ],
    },
};

3. babel 적용하기

webpack의 중요 기능중 하는 바로 babel을 이용해서 최신 자바스크립트 문법을 호환해준다는 것이다. webpack만으로는 번들링을 위한 도구로서 컴파일은 불가능하며 babel 설정, 패키지등이 별도로 필요하다.

babel을 설정하기 전에

babel은 어떻게 작동할까?

관련 내용은 여기를 참고하자.
해당 내용을 정리하자면 바벨의 실제 동작은 플러그인에 의해 실행되며, 사용할 플러그인을 설치하고 바벨 설정파일인 .babelrc에게 "컴파일 시 이 플러그인을 사용해줘" 라고 알려주어야 한다는 것이다. 그럼 .babelrc은 컴파일시 해당 플러그인을 사용하여 코드를 컴파일 할 것이다.
그리고 필요한 문법마다 플러그인을 설치하기에는 번거로우므로 preset을 사용한다. 즉 babel-preset = "plugin을 모아둔 번들"이다.
간단하게 babel/preset 만 설치하고 .babelrc에 추가함으로서 모든 es6 기능 컴파일이 가능하다.

바벨 적용하기

이제 바벨을 적용해보자.
필요한 패키지들을 설치해주어야한다. 바벨 컴파일러인 @babel/core 와 웹팩에서 babel을 사용하기 위한 로더 babel-loader, 그리고 플러그인인 @babel/preset-env를 설치한다.

위에서 babel에 plugin을 설정해줄 때 babel에 환경 설정 파일에 plugin을 추가해주어야한다고 했다. webpack에서 또한 똑같이 적용이 필요하다. babel 로더를 지정할 때 options에 presets에 설치한 @babel/preset-env 를 추가해준다.

마지막으로 webpack이 babel을 사용할 수 있도록 webpack환경설정에 loader를 추가한다.

이제 index.js에 es6문법의 코드를 작성하고 npm start 시 es5문법으로 컴파일된것을 확인할 수 있다

const test = ()=>{
    console.log("TEST!")
}
function test() {\n  console.log(\"TEST!\");

4. 최적화하기

다음으로 webpack으로 코드를 최적화하는 방법이다.
웹팩의 모드에는 개발, 프로덕션 두가지가 있는데 이는 프로덕션모드에서만 가능하다.

우선 프로덕션 모드로 빌드하기 위해 scripts에
production 빌드 명령어를 추가하고 실행한다.

"scripts": {
     ...
    "build": "webpack --mode production"
  },

빌드된 프로덕션 파일은 우리가 작성했던 코드 그리고 개발모드와 다르며 공백이 없음을 확인할 수 있다.

5. code split

js파일을 번들링했을 때, 코드의 크기가 너무 클때는 한번에 로드하는것보다 필요에 따라 분산시켜 가져오는 것이 좋다. 처음에 필요한 코드만 로드한 뒤 필요에 따라 추가적으로 나머지 코드를 불러오는 방식이다. 각각의 추가로 로드되는 코드를 chunk라고 한다.

방법은
1. Entry Points
2. Prevent Duplication
3. 동적 import
가 있다.

1. Entry Points

만약 번들링하는 모듈을 기능에 따라 분리가 가능하다면 여러개의 엔트리포인트를 둘 수 있을 것이다.
entry설정을 사용하여 코드를 여러개의 엔트리로 분리할 수 있다.
그러나 엔트리포인트가 다를때, 각각의 엔트리의 의존 모듈들도 별도로 관리되기때문에 만약 다른 엔트리에서 중복되는 모듈이 많다면 비효율적으로 코드가 증가될 수 있다.

2. Prevent Duplication

SplitChunksPlugin 등을 사용해서 중복 청크를 제거하고 청크를 분할 할 수 있다.
dependOn 옵션을 사용해서 모듈을 공유하게 할 수 있다.

3. 동적 import

일반적으로 react에서 router로 이동하는 page에 적용할 수 있는 방법이다. 페이지를 이동하기 전까지는 해당 파일들이 불필요하므로 router로 이동하고자 할때 로드 후 실행한다는 개념이다.
혹은 유저의 입력, 이벤트에 따라 나타나는 컴포넌트의 경우 import를 동적으로 할 수 있다.

너무 무분별한 code split은 오히려 코드의 번들링의 이유를 해치므로 주의하자

참고
웹팩 이해하기
webpack기초
[번역] babel-preset-env는 무엇이고 왜 필요한가?
10분 만에 웹팩 배우기
webpack-guide

profile
안녕하세요!

0개의 댓글