🥟

コンテナでbunをパッケージマネージャーとして使うんだったらこう書く

に公開

何がしたいか?

今回はJSランタイムとしてbunを使うのではなく高速なnpm互換パッケージマネージャーとして利用することを焦点においた話になります。そのためbunをランタイムや様々な用途で組み込もうとしている用途での記事ではないのでご注意ください。
実現したいことを箇条書きにすると以下です

  • CI/CDの中でbunを高速なnpm互換のパッケージマネージャーとして組み込みたい
  • CI/CDで十分なパフォーマンスを出すためにロックファイルはbun.lockbを使いたい

    開発環境のコンテナでもbunをパッケージマネージャーとして利用して環境を統一したい
”そもそもbunとは”のための説明

Develop, test, run, and bundle JavaScript & TypeScript projects—all with Bun. Bun is an all-in-one JavaScript runtime & toolkit designed for speed, complete with a bundler, test runner, and Node.js-compatible package manager.

公式ドキュメント

答え

# syntax=docker/dockerfile:1
FROM --platform=$BUILDPLATFORM oven/bun:1.1.42-alpine AS bun
FROM node:22.12.0-alpine3.21

WORKDIR /usr/src/bun-sample/

RUN apk --no-cache add wget git unzip vim curl python3 make g++

COPY --from=bun /usr/local/bin/bun /usr/local/bin/bun # bun installしてます

COPY ./bun-sample/package.json ./bun-sample/bun.lockb ./

RUN bun i

ENV NODE_ENV=development

何をしてるか

要点だけ説明

  • ホスト環境がARM64でoven/bunをベースイメージとする際にはプラットフォーム指定しないとうまく動かなかった
    • よく分からない箇所で処理がコケて結構時間を食ってしまった、後日調査予定
  • # bun installしてますのところでマルチステージビルドを使ってbunをバイナリだけを持ってくる
    • phpだとdockerでcomposerを使うときに使ったり、Goだとライブラリのバイナリだけ持ってきたい時に使えたりする手段
    • npm i -g bunはCPUアーキテクチャによる違いで工夫が必要で面倒だったので、マルチステージビルドでサクッと導入
bunのおまけ

今回はbun.lockbを使ったがバイナリなのでdependabotやrenovateなどでうまく検知ができないという問題がある。が、それに対応するためにbunの1.1.39からbun.lockというテキストベースのロックファイルを作成するオプションが追加されている。若干パフォーマンスが落ちる可能性はあるが、dependabotなどのサポートを継続して利用したい場合は--save-text-lockfileをつけてみると良いかも

まとめ

  • bunは速い
    • GitHub Actionsのubuntu-latestランナーでパッケージのインストール時間で検証した
      • npmより2倍速い
      • pnpmより若干速い
  • マルチステージビルドは便利
    • 今回のような恩恵を受けられるポイントがあったり、デプロイなどで最終成果物のサイズを小さくする目的など他にも色んな目的に対して使えそう

参考

Discussion