이 글은 webpack을 다루어 보지 않은 사람들을 위한 가이드다. 다만 webpack2를 기준으로 하며, 기본적인 웹 지식(CommonJS, ES2015 등)은 알고있다고 가정한다.
webpack
webpack은 JavaScript 모듈 번들러(Bundler)다. 번들러는 말 그대로 번들링을 하는 도구를 말한다. 그러면 번들링은 뭘까? webpack 공식 페이지에 있는 그림을 보면 이해에 도움이 될 것이다.
webpack은 별도의 파일로 분리되어 있는 JavaScript 모듈들을 의존성을 통해 하나 혹은 여러 개의 파일로 묶는다. 이것을 번들링이라고 한다. 여기에 여러가지 설정을 더하면 CSS나 이미지도 JavaScript 파일로 번들링할 수 있다.
다른 번들러로는 browserify, rollup.js 등이 있다. 하지만 요즘 프론트엔드 세계에서는 webpack으로 대세가 굳어진 느낌이다.
Hello, world!
먼저 webpack을 가지고 놀기 위한 놀이터 디렉토리를 만들자.
1 | $ mkdir webpack-playground && cd webpack-playground |
다음으로, webpack을 설치한다.
1 | $ yarn add webpack --dev |
yarn이 없다면 npm을 사용해서 설치해도 되지만 package.json이 없기 때문에 npm init
이 선행되어야 한다.
또한 글로벌로 설치해서 CLI를 사용해도 되지만 어차피 실제 협업 환경에서는 로컬로 설치한뒤 npm 스크립트를 이용하는 경우가 일반적이므로 로컬 설치를 권장한다.
그 다음으로는 webpack이 로드할 모듈을 구현한다.
1 | // hello.js |
1 | // world.js |
모듈을 만들어놓기만 하고 쓰지 않는다면 아무 소용이 없다. 위의 모듈을 사용하는 코드를 작성한다.
1 | // entry.js |
평소에 Node.js를 자주 사용해서 CommonJS에 익숙하다면 위의 코드가 어떻게 동작할지 잘 알고 있을 것이다. hello
변수는 아까 구현한 hello.js를 로드하므로 'Hello'
라는 문자열이 되고, world
역시 마찬가지다.
이제 파일을 번들링하기 위해서 npm 스크립트를 써준뒤, 사용한다.
1 | { |
이 상태에서 아래의 명령어를 입력한다.
1 | $ yarn build # 혹은 npm run build |
bundle.js라는 파일이 생겼음을 확인할 수 있다. 이제 이 파일을 HTML 파일에서 로드하면 된다.
1 | <!-- index.html --> |
이 HTML 파일을 웹 브라우저에서 열어보면 Hello, world!
라는 문자열이 출력되는 것을 확인할 수 있다.
Configuration
CLI만 이용해서 webpack을 사용할 수도 있지만 명령어가 금방 복잡해지고 한계가 생기므로 설정 파일을 사용하는 것이 일반적이다.
webpack의 설정파일은 복잡하기로 악명이 높지만.. 늘 그렇듯이 처음에는 단순하게 시작할 수 있다.
1 | // webpack.config.js |
여기까지 왔다면 이 설정파일이 이해 안될 분은 없으리라 생각한다. 정말 최소한의 설정만 해놓은 파일이다. 물론 아래에서 계속해서 덩치가 커질 예정이지만 일단 이 설정파일만 가지고도 번들링을 할 수 있다.
설정파일을 만들었다면 webpack
이라는 명령어만 쳐도 파일을 번들링할 수 있다.
1 | { |
Stylesheet
webpack은 Stylesheet도 JavaScript 파일로 번들링할 수 있다. 물론 CSS는 CommonJS 규격에 맞지 않지만, 자체적인 @import
문도 존재하므로 모듈로 볼 수 있고, 번들링할 수 있는 대상이다.
webpack에서 CSS를 번들링하는 방법으로 크게 두 가지가 있다. 첫 번째로는 HTML의 <style>
태그 안에 CSS를 직접 쑤셔넣는 방법. 두 번째로는 별도의 엔트리 포인트를 만들어서 또 하나의 CSS 파일로 빌드하는 방법. 두 가지 방법 모두 장단이 있으나 이 글에서는 첫 번째 방법만을 소개한다. 만약 두 번째 방법에 대해서 궁금하다면 이 링크를 참조.
style-loader는 정확히 위에 설명한 첫 번째 방식으로 동작하는 로더(Loader)다. 우선 사용하기 위해서 style-loader와 css-loader를 설치하자.
1 | $ yarn add style-loader css-loader --dev |
css-loader는 CSS의 @import
나 url()
문을 CommonJS의 require
처럼 해석할 수 있도록 만들어주는 로더다. CSS를 번들링 하기 위해서는 기본적으로 이 두 가지 로더를 사용해야 한다.
먼저, 로더를 사용하려면 설정파일을 수정해야 한다.
1 | // webpack.config.js |
module
프로퍼티 아래에 약간의 설정을 추가했다. 간단하게 설명하면 .css
확장자로 끝나는 파일을 로드하는 경우 css-loader와 style-loader를 거치도록 하겠다는 의미다. 같은 파일에 대해서 로더는 아래쪽부터 순서대로 동작한다.
이제 불러올 CSS를 작성한다.
1 | /* text.css */ |
1 | /* common.css */ |
이제 이 CSS를 일반적인 CommonJS 모듈 사용하듯이 불러오면 된다.
1 | // entry.js |
웹 브라우저에서 새로고침을 해보면 스타일이 적용된 것을 확인할 수 있다. 특히, 개발자 도구를 켜서 <style>
태그 안에 CSS가 들어간 것을 확인해보자.
ES2015
IE환경을 지원하면서도 ES2015를 쓰기 위해서는 babel 같은 트랜스파일러(Transpiler)가 필수다. babel은 단독으로도 사용 가능하지만 webpack과 함꼐 사용하면 더 편리하다. webpack에서는 ES2015 JavaScript를 babel-loader에 통과시켜서 ES5 이하의 JavaScript로 만든다.
먼저 babel-loader를 사용하기 위해서 먼저 babel-loader를 설치한다.
1 | $ yarn add babel-loader babel-core babel-preset-env --dev |
webpack의 설정도 바꿔야 한다.
1 | // webpack.config.js |
설명을 하고 넘어가야 할 것 같다. 먼저, babel을 사용하기 위해서는 preset을 설치해야 한다. 그 중 babel-preset-env는 설정된 환경에 알맞게 preset을 자동으로 설정해준다. 이 라이브러리를 사용하기 위해서 presets
라는 속성을 사용해서 환경을 설정할 수 있다. 위의 파일에서 설정된 환경은 브라우저 별로 최신의 두 개 버전만을 고려하는 환경이다. 지원하는 브라우저의 리스트는 이 곳에서 확인할 수 있다.
이제부터 프로젝트에 포함된 모든 .js
확장자 파일은 babel-loader를 거치면서 ES5로 트랜스파일된다. 코드를 ES2015로 변경하여 테스트 해보자.
1 | // hello.js |
1 | // world.js |
1 | // entry.js |
빌드를 뒤 결과를 보면, ES5로 컴파일 된 것을 볼 수 있다.
Lint
webpack은 번들러지만 JavaScript 파일을 로드하기 때문에 Lint 작업도 수행할 수 있다. Linter로는 ESLint를 사용한다.
1 | $ yarn add eslint-loader --dev |
ESLint가 글로벌 설치되어있는 상태라면 ESLint의 CLI를 사용하여 쉽게 룰을 생성할 수도 있다. 여기서는 AirBnb 기본 룰을 사용한다.
1 | $ eslint --init |
혹은 다음의 룰을 .eslintrc.js
라는 이름의 파일로 저장한다.
1 | module.exports = { |
ESLint를 돌리기 위해서는 eslint-loader를 webpack 설정 파일에 추가해야 한다. 빌드된 파일을 Lint하는 건 소용없으므로 반드시 babel보다 먼저 eslint를 거치도록 만들어야 한다.
1 | // webpack.config.js |
그리고 바로 enforce
속성이 그 역할을 한다. 이 속성을 'pre'
로 지정하면 JavaScript 파일들이 babel-loader보다 먼저 eslint-loader를 거치게 된다.
ESLint가 제대로 동작하는 지 확인해보기 위해서, 코드를 추가한다.
1 | // entry.js |
제대로 설정했다면 아래처럼 에러가 표시될 것이다.
1 | error Unexpected var, use let or const instead no-var |
npm 모듈 사용하기
webpack은 CommonJS 방식의 모듈 로드를 지원하므로, npm 모듈을 브라우저에서 그대로 사용할 수 있다. 여기서는 유명한 JavaScript 라이브러리인 Lodash를 사용할 것이다.
1 | $ yarn add lodash |
이제 Lodash의 random
함수를 사용하기 위해서 다음과 같이 코드를 수정한다.
1 | // entry.js |
빌드하고 브라우저에서 확인해보면 새로고침할 때마다 랜덤한 숫자가 노출되는 것을 확인할 수 있다.
사족으로, Lodash는 스크립트 용량이 워낙 크기 때문에 import {random} from 'lodash';
같은 식으로 로드하면 Lodash의 완전한 구현을 번들링한다. 따라서 번들링된 스크립트 크기도 매우 커진다. 그러므로 별도의 엔트리 파일을 로드해서 스크립트 사이즈를 최적화하자.
또한, webpack2 에서는 스크립트 사이즈 최적화 기법으로 Tree Shaking을 사용할 수 있다. 직접 짠 코드는 Tree Shaking을 사용하면 되지만, 다른 라이브러리를 불러와서 사용할 때는 Tree Shaking이 안되는 경우가 있으므로 항상 별도의 엔트리 파일을 포함하는 방법을 찾아보자. Tree Shaking에 대해서는 나중에 별도의 글로 쓸 예정이다.
마치며
webpack2의 베타가 끝내고 정식 버전도 릴리즈된지 꽤 시간이 흘렀지만 게으름으로 마이그레이션을 차일피일 미루다가, 최근에야 webpack2를 사용하게 되었다. 일찍이 블로그에 webpack 실전 가이드라는 글을 쓴 적이 있는데, 이 글은 webpack2를 다루지 않으며, 오래된 정보1를 담은 글임에도 아직 많은 사람들이 해당 글로 유입되고 있기 때문에 내용상 거의 중복되지만 이 글을 새로 작성하게 되었다.
여기에 사용된 코드는 GitHub 레포지토리 webpack-guide에 올라가 있으니 참고하시기 바란다.
- 1.물론 그래봤자 1년도 채 안됐다. ↩