npm linkするなら/usr/local/lib/node_modules/もケアすること
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プログラミング をご購入いただけるとありがたいです。スモウルビーの使い方と教え方を学ぶことができる書籍です。特に小・中学校の先生に読んでいただきたいです。
日本中の小・中学生が学校の授業や地域のプログラミング教室でスモウルビーを使っています。みなさんのご協力で、たくさんの子どもたちがハッピーになります。ご協力、よろしくお願いします。