TL; DR#
FONTCONFIG_FILE = "${pkgs.fontconfig.out}/etc/fonts/fonts.conf";
ビルドプロセスでPuppeteerを使いたい#
前回の記事で,静的にビルドしたStorybookに対し,Puppeteerを通じてヘッドレスモードのChromiumを立ち上げ,stories.jsonというファイルを生成する手順を紹介した.
Chromiumを動かすのは面倒な場合がある#
Puppeteerを用いればChromiumの操作の自動化を手軽に行えるが,CI上などでChromiumをインストールするためには,大量の動的ライブラリの存在が要求され,少々煩わしい.
以下は,かつて.circleci/config.ymlに書いていた内容の抜粋である.
$ sudo apt-get install -y \
libatk-bridge2.0-0 \
libatk1.0-0 \
libcups2 \
libgtk-3-0 \
libnss3 \
libx11-xcb1 \
libxcomposite1 \
libxcursor1 \
libxdamage1 \
libxi6 \
libxrandr2 \
libxss1 \
libxtst6
Dockerイメージをビルドする際にもstories.jsonを生成する必要があるため,Dockerfileにもほぼ同じ(sudoを除いただけの)コマンドを記述しており,二重管理になっていた.Nixを用いれば依存関係の解決が簡単に行なえるし,かつdockerToolsを利用すればビルドプロセスをそのままDockerイメージの作成にも流用できるため,NixでChromiumをインストールしてビルドに用いることにした.
The first Nix file#
まず以下のようなNixファイルを用意した.
しかし,これでは$ yarn sb extract ./distを実行した際に失敗してしまう.
効かない$PUPPETEER_EXECUTABLE_PATH#
本題から逸れるが,実はStorybookが環境変数$PUPPETEER_EXECUTABLE_PATHを読んでくれないという問題がある.このため,Puppeteer自身が勝手にChromiumをインストールしようとしては失敗するという自体に直面した.
これは@storybook/apiが内部的にpuppeteerではなくpuppeteer-coreを用いており,puppeteer-coreはpuppeteerとは異なり$PUPPETEER_EXECUTABLE_PATHを考慮しないことに起因する.また,残念なことに,StorybookのCLIにも Chromiumのパスを指定するオプションなどは特に用意されていないため,現状では自前で用意したChromiumを使用することができなくなってしまっている.
この問題に対処するため,以下のコマンドをbuild phaseに追加した.
また,この件に関してはGitHubにissueを立てておいた.
立ち上がらないChromium#
話を本筋に戻す.上記の問題を解決し,自前で用意したChromiumを用いるようにPuppeteerに伝えても,ECONNRESETが発生してしまい,失敗してしまう.どうやらChromiumがうまく立ち上がっていないようである.
普段CI上でNixによるビルドを行いたい場合には,Dockerイメージとしてnixos/nixを用いるのだが,これはAlpine Linuxのイメージを継承しているため,apkコマンドが利用できる.CircleCIにSSHで接続し,デバッグを試みていたところ,おもしろいことに$ apk add chromiumでChromiumをインストールしておきさえすれば,PuppeteerがapkでインストールしたChromiumを使わずとも実行に成功することがわかった.apkを用いてChromiumをインストールする際には100を超える依存が同時にインストールされるので,そのいずれかによって生じる副作用によって何らかの変化が起こっていると考えた.インストールされたパケッジのリストを抽出し,問題の切り分けを行ったところ,fontconfigが犯人であると判明した.fontconfigのインストール時に/etc/fonts/fonts.confが作成されることが原因だったようである.
$FONTCONFIG_FILEを指定する#
Nixでfontconfigをインストールした際には,/etc/以下にファイルを作成するなどといった行儀の悪いことは行われない.fonts.confへのパスは環境変数$FONTCONFIG_FILEによって設定でき,Chromiumもこれを考慮してくれるようだったので,Nixファイルに以下のような変更を加えた.
こうして無事にNixを用いてstories.jsonを伴った静的なStorybookをビルドすることができた.
