Webpack 시작하기

본 포스트는 프로 리액트: React.js를 이용한 모던 프런트엔드 구축부록A - 웹팩을 공부하며 정리한 글 입니다. 문제시 삭제하도록 하겠습니다. 도서에 포함된 칸반 앱의 소스 코드들이 이전 버전의 리액트로 작성되어 있어서, 그대로 따라서 타이핑 하면 수없이 많은 에러들과 부딪힐 수 있습니다. 우리말로 된 리액트 서적이 없다는 점을 감안하더라도 프로 리액트는 리액트를 처음 접하는 입장에서 굉장히 많은 도움이 되는 책입니다. 새롭게 바뀐 리액트 환경에서 칸반 앱을 동작하게 만드는 재미도 쏠쏠합니다. 리액트를 처음 접하는 개발자라면 한번쯤 처음부터 끝까지 찬찬히 일독하기를 조심스레 권해봅니다.

웹팩?!

웹팩은 프로젝트의 구조를 분석하여, 프로젝트에 포함된 모듈과 자바스크립트 파일을 번들로 묶고 패킹하는 모듈 번들러(module bundler)이다. 웹팩은 메인 파일에서 부터 프로젝트의 구조를 분석하는데, require와 import 키워드를 참고해서 프로젝트의 모든 의존성을 조사한다. 로더를 이용해서 각 소스 파일을 처리하고, 프로젝트의 자바스크립트 모듈을 번들로 묶은 자바스크립트 파일을 생성한다. 일반적으로 하나의 파일로 떨군다.

웹팩 설치 및 실행

웹팩을 사용하기 위해서 가장 먼저 비어있는 디렉토리에서 npm init으로 초기화 시켜주고, 웹팩을 설치한다. 이미 package.json 으로 의존성을 관리하고 있다면 npm init 은 생략해도 무방하다.

1
$ npm init && npm install --save-dev webpack

설치된 웹팩은 다음과 같은 형태로 사용한다.

1
$ node_modules/.bin/webpack {최상위 파일} {최종 번들 파일}

아무런 오류 없이 bundle.js 이 생성되었다면 성공적으로 번들링이 수행된 것이다.

구성 파일(webpack.config.js) 작성

웹팩은 다양한 옵션을 제공하며, 로더와 플러그인을 적용하여 소스 코드를 변환할 수 있다. 이와 같은 기능들을 사용하기 위해서 커맨드 라인에서 옵션을 지정하고 웹팩을 실행할 수 있다. 다만 이 방법은 웹팩을 실행할 때마다 사용자가 직접 사용할 옵션을 입력해야 하는 불편함이 있다. 빌드와 관련된 모든 정보를 넣을 수 있는 간단한 자바스크립트 모듈을 한 파일에서 관리하는 편이 훨씬 효율적이다. webpack.config.js에서 웹팩을 설정들을 관리할 수 있다.

1
2
3
4
5
6
7
8
// webpack.config.js
module.exports = {
entry: __dirname + "/app/main.js",
output: {
path: __dirname + "/public",
filename: "bundle.js"
}
}

webpack.config.js 파일에서 웹팩 설정값들을 세팅 해주었지만, 웹팩을 실행시키기 위해서 node_modules/.bin/webpack 을 입력해야 하는 것은 여전히 불편하다. npm을 태스크 러너로 사용해서 긴 명령어를 간단한 명령으로 바꾸어 실행하자. 아래의 예제와 같이 package.json 파일에 scripts 섹션을 추가한다.

1
2
3
4
// package.json
"scripts": {
"webpack": "node_modules/.bin/webpack"
},

이제 npm run webpack을 사용해서 웹팩을 실행시킬 수 있다.

소스맵 생성

웹팩을 사용하면 프로젝트의 모든 자바스크립트 모듈을 하나의 번들 파일로 만들어 사용할 수 있다. 그러나 하나의 파일로 번들링되면, 디버깅 할때 원래 어떤 파일의 어떤 부분에서 문제가 생겼는지 찾기 어렵다는 단점이 있다. 소스맵은 이러한 문제를 해결한다. 번들 파일 내의 코드를 원래 소스 파일과 연결함으로써 브라우저에서 코드를 읽고 디버깅하기 쉽게 만들어 준다. devtool 설정을 이용해서 소스맵을 사용하도록 웹팩을 구성할 수 있다. devtool 에서는 다음과 같은 값들을 사용할 수 있다.

  • source-map
    • 모든 기능이 포함된 완전한 소스맵을 별도의 파일로 생성
    • 최고 품질의 소스맵을 생성하지만 빌드 프로세스가 느리다
  • cheap-module-source-map
    • 별도의 파일에 칼럼 매핑을 제외한 소스맵을 생성
    • 칼럼 매핑을 생략하면 빌드 속도는 향상되지만 디버깅은 불편하다
    • 브라우저 개발자 툴에서는 원래 소스 파일의 행만 가리킬 수 있게 되어 있다
  • eval-source-map
    • eval을 사용해 동일한 파일 안에 전체 소스맵과 소스코드 모듈을 중첩해서 번들로 생성
    • 빌드 시간에 대한 부담없이 모든 기능이 포함된 소스맵을 생성
    • 자바스크립트를 실행할 때 성능과 보안 이슈가 발생할 수 있다
    • 개발 중에는 유용하지만 운영 환경에서 빌드할 때는 사용하지 말 것
  • cheap-module-eval-source-map
    • 소스맵을 가장 빠르게 생성
    • 번들 자바스크립트 파일이 컬럼 매핑을 제외하고 동일하게 인라인으로 포함
    • 자바스크립트 실행 시간에 부정적인 영향을 미치기 때문에 운영 환경에서는 적합하지 않음

웹팩 개발 서버

웹팩은 로컬 환경에서의 개발을 지원하기 위해서 웹팩 개발 서버라는 옵션을 제공한다. 웹팩 개발 서버는 정적 파일을 제공하며, 웹팩 구성에 따라 에셋을 빌드한 후 메모리에 저장했다가 개발자가 소스 파일을 수정하면 자동으로 브라우저를 새로 고치는 간단한 node.js express 앱이다. 다음과 같이 설치할 수 있다.

1
$ npm install --save-dev webpack-dev-server

웹팩 개발 서버는 webpack.config.js 파일의 devServer의 값을 설정해줌으로써 구성할 수 있다. devServer 의 설정 값들은 아래와 같다.

  • contentBase
    • 웹팩 개발 서버가 바라보는 기본 경로는 프로젝트 루트이다. 다른 디렉토리의 파일을 바라보게 하기 위해서 contentBase 값을 설정해준다
  • port
    • 기본값은 8080이며, 별도의 포트를 사용하고자 할 때 설정한다.
  • inline
    • true로 설정하면 작은 클라이언트 엔트리를 번들에 삽입해 페이지가 변경되면 새로 고친다.
  • historyApiFallback
    • 단일 페이지 어플리케이션을 개발할 때 유용한 옵션
    • 기존 에셋과 매핑되지 않는 웹팩 개발 서버에 대한 모든 요청이 /로 라우팅된다.

로더

외부 스크립트와 도구를 통해 소스 파일을 전처리하고 다양한 변경과 변환을 적용하기 위해서 로더를 사용한다. JSON 파일을 일반 자바스크립트로 파싱하거나, ES6를 트랜스파일하는데 사용된다. 뿐만 아니라 리액트의 JSX 파일을 일반 자바스크립트로 변환하는데도 사용할 수 있다. 로더는 별도로 설치해야 하며, webpack.config.jsmodules 키에 값을 설정해줌으로써 사용할 수 있다. modules 에서는 다음과 같은 항목들을 관리해줘야 한다.

  • test(필수)
    • 로더로 처리하기 위해 일치해야 하는 파일 확장자를 비교하는 정규 표현식
  • loader(필수)
    • 로더의 이름
  • include/exclude
    • 로더가 명시적으로 추가하거나 무시할 폴더와 파일을 수동으로 지정하는 옵션
  • query
    • 로더로 추가 옵션을 전달하는데 이용되는 쿼리

바벨(Babel)

바벨은 자바스크립트 컴파일과 도구 지원을 위한 플랫폼이다. 일부 브라우저에서 지원되지 않는 자바스크립트의 버전, 예를 들면 ES6, 등을 사용할 수 있게 해줄 뿐만 아니라, 리액트의 JSX와 같은 자바스크립트 구문을 사용할 수 있게 해준다. 바벨을 독립적으로 실행시킬 수 있는 도구이지만, 웹팩의 로더로 사용할 수 있으며, 그 궁합이 굉장히 좋다.

바벨의 코어 기능은 babel-core라는 npm 패키지로 제공되며, babel-loader를 통해서 웹팩과 통합하여 사용할 수 있다. 또한 ES6 컴파일을 위해서 babel-preset-es2015을 사용할 수 있으며, babel-preset-react를 사용하여 리액트의 JSX를 지원할 수 있게 만들어 준다. webpack.config.js 파일에 다음과 같이 소스 코드를 추가해줌으로써 바벨을 웹팩의 로더로 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
// webpack.config.js
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel'
},
]
},

앞서 언급했던 것처럼 바벨은 원래 독립적인 자바스크립트 모듈이다. 제공하는 기능도 굉장히 많기 때문에 config 설정과 옵션, 조합이 다양하다. 따라서 webpack.config.js 파일 하나에서 바벨 설정까지 처리하면 파일이 지나치게 복잡해질 수 있다. 때문에 일반적으로 .babelrc 라는 바벨 전용 구성 파일을 작성한다.

1
2
3
4
// .babelrc
{
"preset": ["react", "es2015"]
}

플러그인

로더는 웹팩이 빌드 프로세스 중에 로드 하는 각 소스 파일을 하나씩 처리하는 반면 플러그인은 개별 소스파일이 아닌 빌드 프로세스 전체에 영향을 미친다. 플로그인은 빌드 프로세스로 자신을 주입해 커스텀 동작을 추가할 수 있게 해준다.

Hot Module Replacement(HMR)

HRM은 컴포넌트를 실시간으로 조정하고 확인할 수 있게 해주는 기능으로써, CSS와 JS를 수정하면 브라우저에서 페이지를 새로 고치지 않아도 변경 사항이 즉시 브라우저에 반영된다. HMR은 컴포넌트의 코드를 수정할 때 브라우저에서 실시간으로 컴포넌트를 업데이트 할 수 있는 웹팩 플러그 인이며, 제대로 작동하려면 모듈에 HMR을 위한 특수한 코드를 추가해야 한다. 웹팩에서 제공하는 API를 구현하여 자바스크립트 모듈을 교체하게 할 수 있지만, 바벨을 사용해서 편하게 구성할 수 있다. 바벨의 react-transform-hmr 플러그인은 모든 리액트 컴포넌트에 HMR 코드를 삽입하여 리액트 컴포넌트가 변경될 때 마다 브라우저에 즉시 반영되도록 한다.

HMR 기능을 사용하기 위해서 우선 webpack.config.js 파일의 플러그인 설정에 webpack.HotModuleReplacementPlugin() 을 추가하고, derServer 옵션에 hot 매개변수를 true로 설정해준다. 바벨을 사용해서 HMR을 제공하기 위해서 babel-plugin-react-transform, react-transform-hmr 을 설치한다.

1
$ npm install --save-dev babel-plugin-react-transform react-transform-hmr

설치된 바벨의 기능을 사용하기 위해서 아래처럼 .babelrc 파일을 수정해준다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"presets": ["react", "es2015"],
"env": {
"development": {
"plugins": [[
"react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"]
}]
}
]]
}
}
}

production 레벨에서의 웹팩

운영 환경에서도 웹팩을 사용하기 위해서는 일반적으로 별도의 config파일을 생성한다. webpack.config.js 파일에서
devtool, devServer, HMR 구성만 제거 해서 사용해도 된다. 추가적으로 OccurenceOrderPlugin, UglifyJsPlugin, ExtractTextPlugin 플러그인을 적용해서 웹팩의 결과물을 최적화 할 수 있다.

  • OccurenceOrderPlugin
    • 모듈을 식별하기 위한 ID를 제공 가장 자주 이용되는 모듈을 분석한 후 우선순위에 따라 가장 작은 ID를 할당한다.
  • UglifyJsPlugin
    • 웹팩의 결과물로 산출된 번들 파일을 압축하거나 축소한다
  • ExtractTextPlugin
    • 모든 css require/import 를 별도의 css 출력 파일로 옮겨서 자바스크립트에서 스타일을 인라인으로 포함할 필요가 없게 해준다.

마치며

웹팩은 프로젝트에 포함된 모듈을 처리하고, 번들로 묶는 유용한 도구로서 모듈의 의존성 관리를 편리하게 하며, 로더와 플러그인을 통해서 다양한 리소스를 활용할 수 있다. 또한 webpack의 공식 문서를 보면 굉장히 잘 정리되어 있음을 느낄 수 있다. 웹팩은 리액트 커뮤니티에서는 사실상 표준으로 인정받고 있다고 하는데, airbnb를 포함한 꽤 많은 회사들이 웹팩을 사용하고 있다고 한다.

얼마 전부터 웹팩이 적용된 프로젝트(적용은 다른 사람이…)에서 리액트 개발을 진행하고 있는데, 로컬 환경에서의 개발이 이전보다 편리해졌다. 특히 webpack.HotModuleReplacementPlugin()을 덕을 톡톡히 보고 있다. 새로 고침하지 않아도 브라우저가 수정 사항을 반영하고 있어 개발간에 굉장히 편리하다.

References

PreUpdate 어노테이션은 왜 동작하지 않았는가? AngularJS application 테스트

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×