Skip to content

Instantly share code, notes, and snippets.

@x7ddf74479jn5
Last active April 12, 2023 06:00
Show Gist options
  • Save x7ddf74479jn5/07af76b9530099c427737af5365d503c to your computer and use it in GitHub Desktop.
Save x7ddf74479jn5/07af76b9530099c427737af5365d503c to your computer and use it in GitHub Desktop.
GitHub Actions上でPuppeteer利用時"Could not find Chromium"でエラーが出たときの解決法

GitHub Actions上でPuppeteer利用時"Could not find Chromium"でエラーが出たときの解決法

TL;DR

どちらか。

  • node node_modules/puppeteer/install.jsで手動インストール。
  • 諦めてDocker使う。

事象

非Docker環境、GitHub Actions上でVRTをstorycapで実行。storycapが依存しているPuppeteer起動ステップで"Could not find Chromium"とエラー表示される。原因は/home/runner/.cache/puppeteerにChromiumバイナリがないから。

解説

Puppeteerのパッケージにはpuppeteerpuppeteer-coreがあり、puppeteerの方はinstallコマンドを使うと内部的にChromeをインストールして実行パスに追加する。postinstallコマンドで依存パッケージのインストール終了後に実行される。

node_modules/puppeteer/package.json

  "scripts": {
    "build:tsc": "wireit",
    "build:types": "wireit",
    "build": "wireit",
    "clean": "tsc -b --clean && rimraf lib",
    "format:types": "wireit",
    "generate:package-json": "wireit",
    "generate:sources": "wireit",
    "postinstall": "node install.js",
    "prepack": "wireit"
  },

node_modules/puppeteer/install.js

/**
 * This file is part of public API.
 *
 * By default, the `puppeteer` package runs this script during the installation
 * process unless one of the env flags is provided.
 * `puppeteer-core` package doesn't include this step at all. However, it's
 * still possible to install a supported browser using this script when
 * necessary.
 */

const path = require('path');
const fs = require('fs');
const {execSync} = require('child_process');

// Need to ensure TS is compiled before loading the installer
if (!fs.existsSync(path.join(__dirname, 'lib'))) {
  console.log('It seems we are installing from the git repo.');
  console.log('Building install tools from scratch...');
  execSync('npm run build --workspace puppeteer');
}

const {downloadBrowser} = require('puppeteer/internal/node/install.js');

downloadBrowser();

ローカルマシンではPuppeteerをインストール後にChromiumバイナリがインストールされたまま残り続ける。CI上ではワークフロー終了後にコンテナごと削除されるため都度Puppeteerのインストールが必要になる。つまり、node_modulesをキャッシュしなければ問題ないと言える。とはいえ、たいていのワークフローではnode_modulesをキャッシュしたい場合が多いので、当該事象の発生につながる。

解決法

手動インストール

方針

  • ワークフローのPuppeteerを使う前段で準備。
    • キャッシュがないか古いときインストールスクリプトを手動実行する。
    • キャッシュがある場合キャッシュから復元。
  • Chromiumバイナリのインストール先である/home/runner/.cache/puppeteerフォルダをキャッシュする。

node node_modules/puppeteer/install.js

package.json

"scripts":{
  "install:chrome": "node node_modules/puppeteer/install.js"
}

.github/actions/setup-puppeteer/action.yml

name: Setup puppeteer
description: Install Chromium

runs:
  using: composite
  steps:
    - name: Get installed Playwright version
      shell: bash
      id: puppeteer-version
      run: echo "PUPPETEER_VERSION=$( sh .github/scripts/get-puppeteer-version.sh )" >> $GITHUB_OUTPUT
    - uses: actions/cache@v3
      name: Setup puppeteer cache
      id: puppeteer-cache
      with:
        path: ${{ env.PUPPETEER_CACHE_DIRECTORY }}
        key: ${{ runner.os }}-puppeteer-${{ steps.puppeteer-version.outputs.PUPPETEER_VERSION }}
        restore-keys: |
          ${{ runner.os }}-puppeteer-
      env:
        PUPPETEER_CACHE_DIRECTORY: "/home/runner/.cache/puppeteer"
    - name: Install Chrome
      run: |
        if ${{ steps.puppeteer-cache.outputs.cache-hit != 'true' }}; then
          pnpm install:chrome
        fi
      shell: bash

.github/scripts/get-puppeteer-version.sh

#!/bin/bash

cat package.json| grep "\"puppeteer\"" | head -n 1 | tr -d ' \":,' | tr -d 'puppeteer'

# 上と同様の出力を得られるが遅い
pnpm list -D | grep puppeteer | tr -d 'puppeteer '

# VSCode拡張のCode Runnerで計測
# 上:[Done] exited with code=0 in 0.1 seconds
# 下:[Done] exited with code=0 in 2.237 seconds

composite actionにした。やっていることはPuppeteerのバージョンをキャシュのキーにしつつ、キャッシュの有無によって処理を切り替えている。

注意点としてはcomposite action内ではif分岐が使えないのでシェル内に分岐処理を書く。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment