Bunでフロントエンド開発どこまでできるのか
- publishedAt:
- 2024/12/21
- updatedAt:
- 2024/12/21
2024年 ユウトの一人アドベントカレンダーの21日目の記事です。
Intro
BunはJavaScriptやTypeScriptの開発全般を1つのツールで完結させることを目指して設計されています。 サーバーサイドでの開発はDenoやNode.jsの経験からイメージは湧くと思いますが、フロントエンド開発ではどうでしょうか。
今回は、Bunを使ってモダンフロントエンド開発の主要なタスク(バンドル、分割、トランスパイル、ミニファイ、JSX)を試し、どこまで活用できるかを検証してみます。
やりたいこと
今のモダンフロントエンドの開発から顧みて、以下の項目を試してみます。
- Bundle
- Spliting
- Transpile
- Minify
- JSX(TSX)
Bundle
BunのBundle処理についてこちらに書いてあります。 とりあえずドキュメントに書いてある通りに動かしてみましょう。
// app.tsx
import * as ReactDOM from 'react-dom/client';
import {Component} from "./Component"
const root = ReactDOM.createRoot(document.getElementById('root')!);
root.render(<Component message="Sup!" />)
// Component.tsx
export function Component(props: {message: string}) {
return <p>{props.message}</p>
}
このように定義したtsxファイルに対し、CLIかもしくはBun.buildメソッドを使えば良いそう。
せっかくなのでBun.build
を使ってみることにします。
await Bun.build({
entrypoints: ['./app.tsx'],
outdir: './build',
})
bunはtsファイルもそのまま実行可能なので、bun index.ts
という感じで実行すると、entryPointsを基準にバンドルされます。
この時サラッとtsxも書いたので、トランスパイルもやってくれていそうですね。
Code Spliting
バンドルしてくれたはいいものの、ただ一つのJavaScriptファイルにバンドルしただけではパフォーマンスの悪化は目に見えています。 それを回避するために、基本的にはチャンク分割を行いますが、Bunは可能なんでしょうか。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
splitting: false, // default
})
https://bun.sh/docs/bundler#splittingにありました。どうやら先ほどのBun.build時にオプションを渡すだけで良いそうですね。
実際に動かしてみましょう。 以下のようなコードを用意します。
// entry-point-a
import { shared } from './shared.tsx';
console.log(shared)
// entry-point-b
import { shared } from './shared.tsx';
console.log(shared)
// shared.tsx
export const shared = 'shared';
splittingオプションをfalseにした場合は以下のようになります。
// src/shared.tsx
var shared = "shared";
// src/entry-point-a.tsx
console.log(shared);
shared定数が書くjavascriptファイルで定義されるようになります。 ではsplittingオプションをtrueにしてみるとどうでしょうか。
import {
shared
} from "./chunk-1qr3tfrz.js";
// src/entry-point-a.tsx
console.log(shared);
sharedがモジュール化され、各ファイルでimportされるようになりました。
ただこれ、entryPoints基準でしかチャンク分けされないみたいで、 例えばさっきのentry-point-a.tsxとentry-point-b.tsxを最終的にapp.tsxで呼び出した場合、中で共通で使用されているsharedはチャンク分割されませんでした。
なのでReactアプリケーションだと最終的なentryPointsって一つになりがちだと思うので、これだとどうなんだろう。という気持ちが若干あります。 何かしらチャンク分けするための別の仕組みが必要そう...??
Minify
JSXとTSのTranspileはできそうだったので、最後にminifyも見ていきましょう。
https://bun.sh/docs/bundler#minify同じくこちらもドキュメント存在しました。
await Bun.build({
entrypoints: ['./index.tsx'],
outdir: './out',
minify: true, // default false
})
こちらもオプションをtrueにするだけで良さそう。 同じファイルでminifyの有無でファイルサイズどれくらい変わったかは以下の通りです。
// minifyなし
❯ bun getFileSize.ts ./build/app.js
Size: 895958 bytes (874.96 KB)
// minifyあり
$ bun getFileSize.ts ./build/app.js
Size: 367521 bytes (358.91 KB)
ほぼ何も書いていないようなJavaScriptファイルですが、これだけの差が出ました。(Reactだからというのもあるでしょうが。)
まとめ
細かいバグはあると思いますが、おおまかな機能としてはありそうなので、フロントエンドでも案外使えるのかもしれませんね。 Bunの独自構文を使ったらデプロイ先にかなり悩みそうですが。
Bunでフロントエンド開発どこまでできるのか
- publishedAt:
- 2024/12/21
- updatedAt:
- 2024/12/21
0