npm linkするなら/usr/local/lib/node_modules/もケアすること

10 minute read

React + Redux で構築された smalruby3-gui というSPA の開発環境を Docker で用意しています。1つはライブラリ、もう一つがSPAという構成で、npm link を使って前者を後者から利用します。
このとき、Docker イメージであらかじめ /usr/local/lib/node_modules のシンボリックリンクを作っておく必要がありました。

RUN mkdir -p /usr/local/lib/node_modules/ && ln -sf ../../../../app/gui/scratch-vm /usr/local/lib/node_modules/scratch-vm

そのことに気がつくまでに数ヶ月かかってしまったので、備忘録をかねてここに記録しておきます。


もう何年もスモウルビーという Scratch のブロックと Ruby スクリプトを相互変換できるプログラミング学習環境を開発・運用しています。
https://smalruby.app

レポジトリは smalruby3-gui です。Scratch Foundationが開発している scratch-gui をベースにして、Scratch のブロックとRuby スクリプトを相互変換できる機能を追加しています。オープンソースソフトウェアなので、誰でも自由に開発や再配布ができます。

私を含めて、誰でも簡単にスモウルビー自体を開発できるように smalruby3-develop レポジトリで Dockerfile や docker-compose.yml を配布して、基本的には git clone して docker compose build すれば開発環境が整うようにしています。

smalruby3-gui は、React + Redux を利用したSPA です。ビルドするには node.js、Webpackなどが必要です。

また、scratch-vm に依存しています。開発中は npm link で手元の scratch-vm を利用します。

cd path/to/scratch-vm
npm install
npm run build
npm link

cd path/to/smalruby3-gui
npm install
nom link scratch-vm

Docker イメージでは、必要なソフトウェアのうち、OSが提供しているものだけをインストールしています。npm でインストールするものは ランタイムに entrypoint.sh でインストールします。これは /root/.npm とnode_modules をキャッシュするためで、 それらを volume としてマウントしています。

gui/Dockerfile

RUN \
  set -eux \
  && apt update \
  && apt install -y --no-install-recommends \
    build-essential \
    ca-certificates \
    git \
    curl \
    less \
    lv \
    vim

RUN \
  set -eux \
    && apt update \
    && apt install -y gnupg \
    && curl -fSsL https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg \
    && sh -c 'echo deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main > /etc/apt/sources.list.d/google-chrome.list' \
    && apt update \
    && apt install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends

# (省略)

COPY entrypoint.sh /app/gui/entrypoint.sh
RUN chmod +x /app/gui/entrypoint.sh
ENTRYPOINT ["/app/gui/entrypoint.sh"]
CMD npm start

gui/entrypoint.sh

#! /bin/sh -e

if [ ! -e /app/gui/built-scratch-vm ]; then
  (
    cd /app/gui/scratch-vm
    npm ci
    npm run build
    npm link
    touch /app/gui/built-scratch-vm
  )
fi

if [ ! -e /app/gui/built-smalruby3-gui ]; then
  (
    cd /app/gui/smalruby3-gui
    npm ci
    npm link scratch-vm
    npm run build
    touch /app/gui/built-smalruby3-gui
  )
fi

exec "$@"

docker-compose.yml

services:
  gui:
    # (省略)
    volumes:
      - type: bind
        source: .
        target: /app
      - type: volume
        source: root_npm
        target: /root/.npm
      - type: volume
        source: scratch-vm_node_modules
        target: /app/gui/scratch-vm/node_modules
      - type: volume
        source: smalruby3-gui_node_modules
        target: /app/gui/smalruby3-gui/node_modules
# (省略)

volumes:
  root_npm:
  scratch-vm_node_modules:
  smalruby3-gui_node_modules:

このとき、entrypoint.sh を実行して npm install などを行ったプロセスでは問題ないのですが、別のプロセスでは npm run build が失敗します。

エラーの内容は scratch-vm のビルドに必要な hasky がないとかなんとか。嘘でしょとか思って確認すると、 npx hasky は実行できるけど、hasky 単体でシェルから起動することはできない状態でした。

最初は原因がわからず、haskyなんかを使うから悪いとか言い訳をしながら半ば諦め、再ビルドをしたり、docker compose run ではなくて exec でプロセスを使い回したりして問題を先送りにしていました。

それで、数ヶ月放置していたのですが、急に閃きました。scratch-vm で npm link したときに作られた symbolic link が Docker イメージに含まれていないため、プロセスを起動するたびに再作成が必要なことに。

ということで、Docker イメージであらかじめ /usr/local/lib/node_modules に symbolic link を作成して根本的な解決ができました。

RUN mkdir -p /usr/local/lib/node_modules/ && ln -sf ../../../../app/gui/scratch-vm /usr/local/lib/node_modules/scratch-vm

めでたし、めでたし。

ただ、別の問題で upstream の scratch-gui を smalruby3-gui にマージするとスモウルビーが起動しなくなってしまった。絶賛対応中…。

協力者の募集

スモウルビーの開発にご協力いただける方を常に募集しています。

ご協力いただける方は、 contact@smalruby.jp までご連絡いただいてもいいですし、連絡なしで「xxx のブロックに対応しました」というPRを作成してもらってもかまいません。むしろその方が好都合です。

また、 拙著:小学生から楽しむ きらきらRubyプログラミング をご購入いただけるとありがたいです。スモウルビーの使い方と教え方を学ぶことができる書籍です。特に小・中学校の先生に読んでいただきたいです。
小学生から楽しむ きらきらRubyプログラミング

日本中の小・中学生が学校の授業や地域のプログラミング教室でスモウルビーを使っています。みなさんのご協力で、たくさんの子どもたちがハッピーになります。ご協力、よろしくお願いします。

タグ:

カテゴリー:

更新日時: