はじめに

Parcelというモジュールバンドラを触ってみたので、その備忘録になります。

webpack時代の終わりとparcel時代のはじまり

結論から言いますと、機能がシンプルすぎて自分の実務での利用は難しいと感じました
そのため、現時点(v1.1.0)ではwebpackの代わりにはならないです
とは言えども、webpackと比べてビルドが楽なので、個人でちょっとしたコードを書いてビルドしたい時には便利なツールだと思いました。

本記事の目的は以下の通りです。

  • Parcelの基本的な使い方を理解する。
  • webpackとどんなところが異なるのかをざっくり理解する。

解説に利用しているコードの最終形態はGitHub上にあります。

parcel-tutorial

本記事の前提や注意点

  • v1.1.0時点で書いた記事になります。
  • Parcelの使い方は公式ドキュメントの内容を、より丁寧に解説したものになります。そのため、公式ドキュメントで基礎が理解できるのであればこの記事を読む必要はありません。
  • webpackなどのモジュールバンドラを触ったことがある人向けの記事のため、モジュールバンドラ自体の説明は省きます。
  • webpackやモジュールバンドラの基礎について学習したい方はこちらの記事(webpack 入門)をご覧ください。
  • 本記事ではParcelのことを「モジュールバンドラ」と説明しています。他の記事や公式では「ビルドツール」や「アプリケーションバンドラ」などと説明されていますが、言葉の意味合いはあまり変わらないです。とりあえず「複数のファイルを1つ(もしくは複数)にまとめてくれるツール」という認識さえあれば問題ありません。

Parcelとは

モジュールバンドラのこと。読み方はパーセル(のはず)。

Parcelの特徴(webpackとの違いは何か)

Parcelには以下のような特徴がある。

  • ビルド速度がwebpackと比べてかなり速い
  • webpack.config.jsのような設定ファイルが必要ない
  • JavaScript以外のファイル(HTMLなど)をエントリーポイントに指定できる

上記のようにwebpackの辛さ(設定ファイルの肥大化、規模が大きいとビルド速度が遅いなど)を解消しているモジュールバンドラ。

もちろん、辛さを解消したからと言って全ての点がwebpackより優れているわけではない

ビルド速度がwebpackと比べてかなり速い

公式のベンチマークによると、キャッシュを利用するとwebpackの約8倍

webpack.config.jsのような設定ファイルが必要ない

以下のようにエントリーポイントに対してparcelを実行すれば、ファイルがバンドルされる。

parcel app.js

JavaScript以外のファイル(HTMLなど)をエントリーポイントに指定できる

任意のファイルをエントリーポイントに指定できるらしいが、公式ではJavaScriptかHTMLファイルをエントリーポイントにすることはお勧めしていた。

Parcelを利用してみる

Parcelを利用してモジュールをバンドルしたファイルを出力してみる。
以下は出力までのイメージ図。

parcel-image.png

webpackの場合、cssや画像なども1つのJavaScriptファイルにまとめられて出力される。
一方でParcelの場合、依存関係を解決したファイルがそれぞれ出力される。
そのため、今回は4つのファイルが出力される。

Parcelのインストール

npmか、yarnでインストールできる。

npm install -g parcel-bundler
yarn global add  parcel-bundler

ディレクトリ構成

今回Parcelを利用するディレクトリ構成は以下を前提とする。

.
├── .babelrc
├── package.json
├── public
└── src
    ├── scss
    │   └── style.scss
    ├── images
    │   └── parcel.png
    ├── index.html
    └── js
        ├── app.js
        └── modules
            └── add.js

必要なパッケージのインストール

パッケージをローカルインストールするため、package.jsonは以下のどちらかのコマンドで生成する。

npm init
yarn init

Babel

ES2015のコードをES5に変換するため、Babelをインストールする。
以下のどちらかのコマンドでインストール。

npm i babel-preset-env -D
yarn add babel-preset-env -D

次にBabelの設定ファイルである.babelrcを設置する。

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

webpackではBabelで変換するために、babel-loaderをインストールし、webpack.config.jsbabel-loaderを利用する設定を記述する必要があった。

一方Parcelは.babelrcを検出するとBabelでの変換を自動的に実行するため、これでBabelを利用する準備はできた。

node-sass

scssをcssに変換するため、node-sassをインストールする。
以下のどちらかのコマンドでインストール。

npm i node-sass -D
yarn add node-sass -D

こちらもParcelが自動でnode-sassを利用して変換してくれるため、これで準備完了。

各ファイルの詳細

index.html(エントリーポイント)

エントリーポイント。このファイルをエントリーポイントとしてparcelコマンドを実行すると読み込んでいるapp.jsに対してもビルドが実行される。

src/index.html
<html>
<head>
  <meta charset="utf-8">
  <title>Parcel tutorial</title>
</head>
<body>
  <h1>Parcel</h1>
  <div class="parcel"></div>
  <script src="js/app.js"></script>
</body>
</html>

app.js

add.jsを読みこんで数値を計算したり、style.cssを読み込んでHTMLにスタイル適用しているメインのJavaScriptファイル(webpackでいうエントリーポイント)。

src/js/app.js
import '../scss/style.scss';
import add from './modules/add';

const number1 = 400;
const number2 = 600;
const total = add(number1, number2);

console.log(total);

add.js

引数のnumber1number2を合算して返すモジュール。

src/js/modules/addition-calculator.js
export default function add(number1, number2) {
  return number1 + number2;
}

style.scss

index.htmlに適用するスタイルが記述されたモジュール。

src/css/style.scss
$baseColor: #000;

body {
  background: $baseColor;

  h1 {
    margin: 0;
    padding: 0;
    color: #fff;
    text-align: center;
  }

  .parcel {
    width: 400px;
    height: 374px;
    margin: 0 auto;
    background: url('../images/parcel.png');
  }
}

parcel.png

style.scssから読み込んでいる画像(モジュール)。

parcelコマンドでバンドルされたファイルを出力

上記構成のpackage.jsonが存在する階層でparcelコマンドを実行すれば、バンドルされたファイルが出力される。

デフォルトだと、バンドルしたファイルはdistディレクトリに出力されるが、今回はpublicディレクトリに出力させたいため、以下のようにオプションをつけて実行する。

parcel src/index.html -d public

実行すると、以下のようにpublicディレクトリにバンドルされたファイルと.cacheディレクトリにキャッシュファイルが出力される。

.
├── .babelrc
├── .cache
│   └── fd1fb8126031fa8d090710737434e806.json
├── package.json
├── public
│   ├── dddf7ef8a771ea836c5c4ad7d53dfb78.css
│   ├── dddf7ef8a771ea836c5c4ad7d53dfb78.js
│   ├── e55a1d909b7adad3efe4170b8bfee1d8.png
│   └── index.html
└── src
    ├── scss
    │   └── style.scss
    ├── images
    │   └── parcel.png
    ├── index.html
    └── js
        ├── app.js
        └── modules
            └── add.js

バンドルされたファイルを確認する

出力されたindex.htmlは以下の通り。

public/index.html
<html>
<head>
  <meta charset="utf-8">
  <title>Parcel tutorial</title>
<link rel="stylesheet" href="/public/dddf7ef8a771ea836c5c4ad7d53dfb78.css"></head>
<body>
  <h1>Parcel</h1>
  <div class="parcel"></div>
  <script src="/public/dddf7ef8a771ea836c5c4ad7d53dfb78.js"></script>
</body>
</html>

同じくpublicディレクトリに出力されたdddf7ef8a771ea836c5c4ad7d53dfb78.cssを読み込む記述が追加されている。
また、dddf7ef8a771ea836c5c4ad7d53dfb78.jsを読み込んでおり、依存関係を解決していることがわかる。

バンドルされたファイル(ページ)をブラウザで確認する

parcelコマンド実行時にサーバーも起動するため、http://localhost:1234/にアクセスしてバンドル後のindex.htmlを確認できる。

parcel2.jpg

コンソールは表示され、スタイルも適用され、画像も読み込まれているため、正常に動作していることがわかる。

また、ファイルはwatchされているため、以下のようにファイルの更新をすればリロードされる。

watch.gif

サーバーを起動せずにファイルだけwatchしたい場合は以下のようにコマンドを実行する。

parcel watch src/index.html -d public

webpackと比べてみてParcelはどうなのか(webpackの代わりになるのか)

ただ単純にバンドルされたファイルを出力されるまではwebpackより楽だった。
しかし、現時点(v1.1.0)では以下のような理由で自分の実務で利用するのは難しく、webpackの代わりにはならない。

  • 出力先や出力するファイル名を指定できない
  • 複数のhtml(エントリーポイント)から読み込む共通のバンドルファイルを出力できない
  • webpackでいうCommonsChunkPluginexternalsなどに該当する機能がない

出力先や出力するファイル名を指定できない

上記の例のように、依存関係を解決したファイルは全て同じディレクトリ(今回の例だとpublicディレクトリ)に出力される。
「画像やcssだけは別のディレクトリに出力する」などができない。
また、出力するファイル名も指定できない。

複数のhtml(エントリーポイント)から読み込む共通のバンドルファイルを出力できない

index.htmlabout.htmlpage.htmlなどの複数のhtml(エントリーポイント)から読み込む共通のバンドルファイルを出力できない。
そのため、処理は共通でもエントリーポイントの数に応じたバンドルファイルを出力する必要がある。

webpackでいうCommonsChunkPluginexternalsなどに該当する機能がない

CommonsChunkPluginexternalsなど、実務で利用しているwebpackの様々な機能がParcelにはないため、Parcelを利用できない。

終わり

あくまでv1.1.0時点で書いた記事ですので、将来はもっと使いやすくなっている可能性もあります(機能が増えて結局複雑になる可能性もあります)。興味がある方はissuesPull Requestを追うことをお勧めします。

まだまだwebpackを学習しても無駄ではないので、webpackを学習したい方はこちらの記事をどうぞ。

webpack 入門