Preactで始める軽量コンポーネント指向開発 第1回 Preactの特徴
PreactはReactとほぼ同等の機能を持ち、Reactよりもさらに軽い動作が期待できるUIライブラリです。第1回目はReactとの関係性とPreactの導入について解説します。
- カテゴリー
- UIフレームワーク >
- React/Preact
発行
はじめに
本シリーズでは、PreactというUIライブラリについて解説していきます。
Preactは、軽量版Reactを謳うライブラリであり、現在Google社で働いている@_developit氏によって開発されました。発音としては「プリアクト」が一般的なようです。
この記事を執筆している現在の最新バージョンは10.4.5
です。
なお、以降で紹介するサンプルコードは以下のリポジトリにまとめられています。参考にしてください。
Preactではじめる軽量コンポーネント指向開発
PreactとReactの関連性
Preactは、その名前から、また「Fast 3kB alternative to React with the same modern API」というコピーからも推測できるとおり、Reactに関連があります。
Reactは、過去にCodeGridでも取り上げたことがあるUIライブラリですが「その違いは? ReactとPreact、どっちが良いの?」と思った人も多いでしょう。
その違い、Preactが開発された理由を知るためには、まずはReactについておさらいしなければなりません。
Reactというエコシステム
そもそもReact本体(npmから利用できるパッケージとしてのreact
)は、汎用的なUI構築のためのライブラリです。
Reactで作ったコンポーネントをどの環境で利用するか、つまりコンポーネントをどのレンダラー(実行環境)で利用するかは、我々に委ねられています。
代表的なレンダラーは次のとおりです。
- Webブラウザ用のReact DOM(
react-dom
) - ネイティブアプリ用のReact Native(
react-native
)
レンダラーはもちろん自作することもできます。
ことWeb開発において「Reactを使う」ということは、暗黙的に「react
とreact-dom
レンダラーをセットで使う」ということになります。
このreact
とreact-dom
がやっていることを、これから解説するPreactもやっているのですが、その方法に違いがあります。
ReactとPreactの違い
Reactとの違いについては、公式サイトにも個別のページが用意されていますが、ここではその要点を抜粋して説明します。
最大の違いは、Reactがクリックなどのイベントシステムを独自実装している一方、PreactではDOM本来のAPI(addEventListener()
など)を利用しているところです。
その結果、Preactのファイルサイズはとても小さくなっています。
BundlePhobiaというnpmのパッケージがどれくらいの大きさなのかを可視化するサイトがあるのですが、そのサイトでのそれぞれのファイルサイズ(MINIFIED+GZIPED)は次のとおりでした。
パッケージ名 | 容量 | 結果 |
---|---|---|
[email protected] |
2.6kB | 結果 |
[email protected] |
35.9kB | 結果 |
[email protected] |
4kB | 結果 |
もちろんそのパッケージに含まれるすべての機能を利用する場合の数値であり、実際の利用時にはもう少し小さいはずですが、それでもその差は歴然です。
そのほかの違いですが、パッケージとしてのpreact
は、react
とreact-dom
が備えるすべてのAPIをそっくりそのまま実装しているわけではありません。ここは少し冒頭のコピーが誤解を招くところかもしれません。
まとめるとPreactは「ブラウザ独自のAPIを利用しつつ、必要最小限のAPIを選びぬいた分だけ軽い、ブラウザ専用のReact」というわけです。
preact/compat
という互換レイヤー
PreactはAPIを厳選しているため、Reactをターゲットにして作られた周辺ライブラリは、Preactを利用したプロジェクトでそのまま使えないのも事実です。
また、Reactで作られた既存のアプリケーションをPreactで置き換えたいと思っても、存在しないAPIを使っていた場合は移行の障壁になってしまいます。
Reactとの互換性を重視して、Preactにはpreact/compat
という互換レイヤー*が同梱されています。
*注:古いパッケージ
preact-compatというリポジトリとパッケージがありますが、これは古いバージョン向けです。最新版のpreact
パッケージでは、preact/compat
というネームスペースに同梱されているので、別途インストールの必要はないです。
このpreact/compat
というパッケージを、WebpackやRollupなどのバンドラの設定でエイリアス指定し、react
とreact-dom
の代わりに指定します。
webpack.config.jsでの設定例
const config = {
"resolve": {
"alias": {
"react": "preact/compat",
"react-dom/test-utils": "preact/test-utils",
"react-dom": "preact/compat",
},
}
}
詳細な設定方法については各バンドラのドキュメントを参照してください。併せて公式サイトのガイドも参考にしてください。
このエイリアス設定により、各ライブラリ側が明示的にReactに依存したコードのままで、Preactを利用することができるというわけです。
preact
単体よりはファイルサイズがわずかに大きくなりますが、安全に既存のReactアプリケーションの軽量化に取り組むことができます。なお、使用する周辺ライブラリを当初からPreactでの利用を想定しているものに絞るならば、もちろんpreact/compat
を使う必要はありません。
このシリーズでもpreact/compat
は利用せず、preact
のみで扱えるAPIを解説します。
Preactを使ってみよう
それでは実際に、Preactを使ったコードを動かしてみましょう。
まずは最小構成のコードです。
Preactを用いた最小構成のコード例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Minimum</title>
</head>
<body>
<script type="module">
import { h, render } from "https://unpkg.com/preact?module";
const app = h(
"div",
null,
...[h("h1", null, "Hello Preact!"), h("p", null, "Minimum code.")]
);
render(app, document.body);
</script>
</body>
</html>
これは、次のようなDOMツリーをbody
要素に描画するだけのシンプルな例です。
HTML要素を描画する(実行結果)
<div>
<h1>Hello Preact!</h1>
<p>Minimum code.</p>
</div>
次のような記述で、CDNに公開されているES Modules版のPreactを利用することで、バンドラ要らずでアプリケーション開発が始められます。
CDNのES Modules版のPreactを使用する
import { h, render } from "https://unpkg.com/preact?module";
次の部分がHTMLを記述している部分なのですが、通常のHTML要素とはかけ離れた書き方をしなければなりません。
HTMLの記述部分(抜粋)
const app = h(
"div",
null,
...[h("h1", null, "Hello Preact!"), h("p", null, "Minimum code.")]
);
h()
はDOMツリーを構成する要素を作り出す関数createElement()
のエイリアスなのですが、このままでは少し複雑なHTMLを記述しようとするだけでも苦労しそうです。
より直感的なHTMLの記述でコンポーネントを書けるようにするためには、いくつかのやり方があります。
htm
を使う
まずは、おなじくPreactの作者が開発しているhtm
というパッケージを紹介します。
先ほどの最小構成コード例と同じことを、htm
を使って書き換えるとこうなります。
import文のインポート先をhttps://unpkg.com/htm/preact/standalone.module.js
に変更しています。これでCDN版のhtm
が使えるようになります。
htmを用いた最小構成のコード例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Minimum w/ htm</title>
</head>
<body>
<script type="module">
import {
html,
render,
} from "https://unpkg.com/htm/preact/standalone.module.js";
const app = html`
<div>
<h1>Hello Preact!</h1>
<p>Minimum code using htm.</p>
</div>
`;
render(app, document.body);
</script>
</body>
</html>
変数app
に代入している値を見ると、DOMツリーそのままな直感的な記述ができているのがわかると思います。
appに代入している値(引用)
const app = html`
<div>
<h1>Hello Preact!</h1>
<p>Minimum code using htm.</p>
</div>
`;
同一ではありませんが、やっていることはlit-html
というパッケージが実現していることと同一です。lit-htmlに関しては別の記事があるので、ぜひとも参考にしてみてください。
このhtm
はPreact専用のパッケージではなく、単体でも利用することもできますが、この例ではpreact
が同梱された版を利用しています。
こちらもバンドラが不要でアプリケーションを開発することができるため、おすすめの方法です。
JSXを使う
もう一つの方法として、最後にJSXを使う方法を紹介します。
ReactやVueなど、さまざまなライブラリでも利用される記法なので、馴染みがある人も多いかもしれません。CodeGridでも過去にその記法について紹介したことがあります。
ただしJSXを利用する場合、Babelなどのトランスパイラでの変換が必須となってしまいます。
JSXを使ったコードに書き換えると、このようになります。
JSXを用いた最小構成
import { h, render } from "https://unpkg.com/preact?module";
const App = () => (
<div>
<h1>Hello Preact!</h1>
<p>Minimum code using JSX.</p>
</div>
);
render(<App />, document.body);
Babelでの変換の都合上、.js
ファイルのみを抜粋しています。
Babelを使ってPreactのコードを変換するときに注意すべきはその設定です。
Babelの設定
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"pragma": "h",
"pragmaFrag": "Fragment",
}
]
]
}
React用のプラグインを使って、オプションを指定するかたちで、Preactのコードを変換します。React用のプラグインではpragma
のデフォルト値は、React.createElement
、pragmaFrag
のデフォルト値は、React.Fragment
です。これをPreact用に置き換えて、それぞれh
、Fragment
としています。
Babel自体の使い方や、各種バンドラからBabelを使う方法については、CodeGridの過去記事にも扱ったものがありますので参考にしてみてください。
補足:esbuild
本シリーズのデモのリポジトリでは、Babelではなくesbuild
を使ってビルドしています。esbuild
を利用する場合でも、Babelの設定と同じようにPreactのための指定は行っています。
こういったバンドラの設定が面倒な場合は、preact-cli
を使うことでもセットアップの手間をスキップできます。
よければこちらも参考にしてみてください。
補足:JSX? バンドラ? Babel?
ここまで読んで、「JSX? バンドラ? Babel?」と思った人向けに。詳細はそれぞれの記事を確認していただきたいのですが、ここでも簡潔に説明しておきます。
Webアプリの場合、ブラウザが最終的に実行するのはあくまでJavaScriptです。JSXは、JavaScriptが記述できるものの、それ単体ではJavaScriptとして実行できません。試しにやってみると、HTMLライクな記述の部分でSyntaxエラーになるはずです。
つまり、開発効率のために、我々はJavaScriptを直接使用することを放棄したのです。その代わり、その工程をバンドラ(というよりBabelなどのトランスパイラ)に任せることで、つじつまを合わせています。
この工程では、いわば大掛かりな文字列置換が行われており、もはやなんでもできてしまいます。たとえば日本語で適当に書いたコード文字列を、きちんとしたJavaScriptに変換して利用することも、仕組み上は可能です。
まとめ
今回の記事では、Reactの使い勝手はそのままに、ファイルサイズを劇的に減らすことができるPreactとその導入について解説しました。
ファイルサイズが小さいというのはよいことです。2020年とはいえ、世界の誰しもが高スペック端末と安定したインターネット環境で暮らしているわけではありません。
ファイルサイズが小さいということは、より速くランタイムコードを読み込むことができるだけでなく、理論上はコードパスが短くなるはずで、実行速度にもよい影響があると考えられます。
さて、次回からは、いよいよPreactを使ったコンポーネントの作り方を解説していきます。Preactのシリーズではありますが、Reactのユーザーにも得るところがあるような構成にしていくつもりです。