HEROPY
Tech
{{ scrollPercentage }}%

Parcel - 쉽고 빠르고 강력한 웹앱 번들러 - SASS / PostCSS / Babel / Production

parcel

2017년 여름에 등장한 Parcel.js는 새로운 웹 애플리케이션 번들러 입니다.
기존에 많이 사용하던 Webpack이나 Gulp와 다르게 별도 설정 없어도 빠르게 빌드가 가능합니다.
빌드를 위해 번들러를 학습하는 시간을 많이 줄일 수 있습니다.

특징

빠른 빌드 실행

별도의 설정 없이 진입 파일(Entry File)만 지정하면 바로 빌드(Build) 합니다.

$ parcel index.html

빠른 번들 속도

멀티코어 컴파일이 가능하고, 재시작을 하더라도 캐시를 이용하여 빠르게 리빌드(Rebuild)를 할 수 있습니다.

첫번째 빌드 속도: 4.21초
Parcel Build

재시작 후 빌드 속도: 0.769초
Parcel Rebuild

Assets(애셋) 기반 번들링

HTML, CSS, JavaScript 같은 특정 유형의 애셋을 지원합니다.
비슷한 유형의 애셋은 같은 번들로 출력하고 다른 유형의 애셋은 자식 번들로 만들어 부모 번들에 참조합니다.
예를들어 main.js파일에서 SCSS 파일을 가져오기(import './scss/main.scss') 했다면 다른 번들(.js파일과 .css파일)로 만들어지고 참조를 남깁니다.

자동 변환

가장 많이 사용하는 Babel, PostCSS(특히 Autoprefixer) 같은 트랜스파일러들을 내장 하여 지원합니다.
모듈 안에 .babelrc, .postcssrc 같은 설정 파일들을 발견하면 자동으로 변환합니다.

HMR(Hot Module Replacement)

런타임 중 페이지를 새로고침 하지 않고도 모듈을 자동 업데이트하는 HMR(Hot Module Replacement)이 내장되어 있습니다.
(자동 업데이트가 실패하면 새로고침 합니다)

설정 없이 코드 분할(Splitting)

Dynamic import() function syntax proposal

Dynamic import 함수 import()를 사용하면 코드를 분할(Splitting)하여 빌드합니다.
이는 require(), import와 비슷하게 사용하며 Promise를 반환합니다.
즉 모듈을 비동기 로드할 수 있습니다.
아래에서 살펴볼 예제들 중 하나를 응용하여 Dynamic import 함수를 사용해 보겠습니다.

// msg.js
export const msg = {
  hello: 'Hello Parcel Dynamic import!!'
};
// main.js
import('./msg')
  .then(function (module) {
    console.log(module.msg.hello);  // 'Hello Parcel Dynamic import!!'
  });

위와 같이 Dynamic import 함수를 사용하면 아래와 같이 파일이 분할 됩니다.
하나는 main.js의 번들이고, 나머지 하나는 msg.js의 번들입니다.

File Splitting

제품화(Production)

개발이 완료되고 배포용 빌드(제품화)를 하게되면 자동 으로 Minify(압축)와 Uglify(난독화)를 활성화하여 실행합니다.
물론 다음과 같이 비활성화도 가능합니다.

$ parcel build entry.js --no-minify

설치

특징들을 알아봤으니 이제 직접 설치하여 사용하겠습니다.
Global로 설치합니다.

NPM 설치

$ npm install -g parcel-bundler

Yarn 설치

$ yarn global add parcel-bundler

프로젝트 시작하기

간단한 Parcel 앱을 만들어 보겠습니다.
Parcel-App이라는 폴더를 만들고 package.json를 만들어 줍니다.

$ mkdir Parcel-App
$ cd Parcel-App
$ npm init

다음의 구조를 만들어 주세요.

Parcel-App
  ├─src
  │  ├─main.css
  │  └─main.js
  ├─index.html
  └─package.json
<!-- index.html -->
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <h1>Hello Parcel.js!</h1>
  <script src="./src/main.js"></script>
</body>
</html>
/*main.css*/
h1 {
  color: tomato;
}
// main.js
require('./main.css');
console.log('Hello Parcel!');

Parcel로 빌드하기 위해서 단지 진입 파일을 선택하면 됩니다.

$ parcel index.html

브라우저에서 http://localhost:1234 에 접속하면 빌드된 페이지를 볼 수 있습니다.
만약 포트번호를 변경하고 싶다면 -p <port number> 옵션으로 덮어쓸 수 있습니다.

$ parcel index.html -p 9876

http://localhost:9876 으로 접속할 수 있습니다.

SCSS(SASS) 사용하기

SCSS를 컴파일 하기 위해 node-sass 모듈을 설치하겠습니다.

$ npm install --save node-sass

설치가 완료되었다면 모듈이 제대로 동작하는지 확인해 보겠습니다.
프로젝트 구조를 살짝 바꿔봅시다.

Parcel-App
  ├─src
  │  ├─scss
  │  │  ├─main.scss
  │  │  └─_config.scss
  │  └─main.js
  ├─index.html
  └─package.json
/*_config.scss*/
$color-primary: royalblue;
/*main.scss*/
@import 'config';

h1 {
  color: $color-primary;
}

scss 디렉토리를 생성했으니 가져오기 경로를 변경하세요.

// main.js
require('./scss/main.scss');
console.log('Hello Parcel!');
$ parcel index.html

잘 동작하나요?
별도 설정이 없어도 모듈만 설치하면 바로 사용할 수 있습니다.

PostCSS 사용하기

이번엔 PostCSS로 CSS를 변환하여 사용하겠습니다.
PostCSS plugin 중에서는 Vendor Prefix(공급 업체 접두사)를 제공하는 autoprefixer를 추가합니다.

$ npm install --save autoprefixer

편집기가 파일을 올바르게 해석할 수 있도록 .postcssrc 파일을 생성합니다.

Parcel-App
  # ...
  │  └─main.js
  ├─.postcssrc
  ├─index.html
  └─package.json
/*.postcssrc*/
{
  "plugins": {
    "autoprefixer": true
  }
}

Vendor Prefix가 잘 적용되는지 확인해 보겠습니다.
최근에 많이 사용하는 FlexBox 기능을 적용하겠습니다.

/*main.scss*/
@import 'config';

h1 {
  color: $color-primary;
  display: flex;
  justify-content: center;
  align-items: center;
}
$ parcel index.html

Vendor Prefix 적용 유무를 확인하기 위해 dist 디렉토리에 있는 빌드된 CSS 파일을 열어보겠습니다.

/*dist/a9b13cfdff4b53240fb7925101bb19f2.css*/
h1 {
  color: royalblue;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-box-pack: center;
      -ms-flex-pack: center;
          justify-content: center;
  -webkit-box-align: center;
      -ms-flex-align: center;
          align-items: center; }

-webkit-, -ms- 같은 Vendor Prefix가 적용되었습니다.

Babel 사용하기

Babel을 설치하여 ES6 문법을 사용합시다.

$ npm install --save babel-preset-env
Parcel-App
  # ...
  │  └─main.js
  ├─.babelrc
  ├─.postcssrc
  ├─index.html
  └─package.json

프로젝트 루트에 .babelrc 설정 파일을 만들고, ES2015+ 사용을 위해 preset 활성화를 해줍니다.

/*.babelrc*/
{
  "presets": ["env"]
}

역시 구조를 약간 수정하겠습니다.

Parcel-App
  ├─src
  │  ├─js
  │  │  ├─main.js
  │  │  └─msg.js
  │  └─scss
  │     ├─main.scss
  │     └─_config.scss
  ├─.babelrc
  # ...
// msg.js
export const msg = {
  hello: 'Hello Parcel with Babel!!'
};
// main.js
import '../scss/main.scss';
import { msg } from './msg';

console.log(msg.hello);

변경된 구조에 맞게 호출 경로도 같이 수정합니다.

<!-- index.html -->
<!-- ... -->
  <h1>Hello Parcel.js!</h1>
  <script src="src/js/main.js"></script>
</body>
</html>
$ parcel index.html

개발자 도구 Console에 'Hello Parcel with Babel!!' 메시지가 잘 보이나요?

만약 개발이 완료되고 배포용 빌드(제품화)를 원한다면 다음과 같이 입력합니다.
코드의 Minify(압축)와 Uglify(난독화)를 자동으로 실행합니다.

$ parcel build index.html