Nodejs x Alpine x DockerでScratch3.0の独自Extensions(拡張機能)を作成する開発環境を整える


2020/08/18

今回は
弊社のプログラミング教育事業の一環として利用しているScratch3.0のエクステンションを自作するDockerでの環境づくりに関して解説します。


準備作業

まずはScratch3.0をビルドするためのベースとなるDockerイメージを構築していきます。

なお、本記事の内容では
dockerおよびdocker-composeを手元のPC上で利用できることを前提としております。

これらのインストール方法・使い方などは解説しませんので、他のサイトなどで検索ください。

参考で手元のDebianOSでのインストール状況は、

            
            $ docker --version
Docker version 19.03.8, build afacb8b7f0
$ docker-compose --version
docker-compose version 1.16.1, build 6d1ac21
        
です。

Dockerfileとdocker-compose.yml

早速Scratch3.0開発用のDockerイメージをビルドしていきましょう。

首題の通りで軽量な開発環境が好ましいので
alpineベースで利用します。

ほぼ
公式の'node'イメージで動作しますのでどれを引っ張ってきても動作するはずです。

Dockerfile

今回は至ってシンプルなdockerfileファイルです。

ポイントとしては
webpackをグローバルにnpmインストールして利用する使い方をします。

これはScratch3.0がwebpackでパッケージビルドされるためです。

            
            FROM node:12.16-alpine3.11

WORKDIR /usr/src/app

ENV NODE_ENV=development

RUN apk update && apk upgrade && apk add --no-cache \
    bash git openssh python2 curl

RUN npm i -g webpack webpack-cli webpack-dev-server
        

docker-compose.yml

続いてdocker-compose.ymlです。

生のDockerコマンドをオプション付で叩いてもいいのですが、プロジェクト毎に毎回長いコマンドオプションが覚えてられないので
docker-composeは大変重宝します。

            
            version: '3'

services:
  app:
    image: scratch3:12.16-alpine3.11
    build: .
    user: "node:node"
    environment:
      NODE_ENV: development
    ports:
      - 8601:8601
    volumes:
        - ./:/usr/src/app
    tty: true
        
なお、docker-composeでのサービス名はappとしています。

また、イメージのタグ名
12.16-alpine3.11はnode-alpineのベースイメージのタグと合わせておくと、後々アップグレードする際にわかりやすくなると思います。

Dockerイメージのビルド・起動・停止

初回はこのイメージをビルドする必要があります。

Dockerfileとdocker-compose.ymlのあるルートディレクトリにおいて以下のコマンド、

            
            $ docker-compose build
Building app
Step 1/5 : FROM node:12.16-alpine3.11
 ---> 927d03058714
Step 2/5 : WORKDIR /usr/src/app
 ---> Using cache
 ---> 135d504707ce
#中略
+ webpack-cli@3.3.12
+ webpack-dev-server@3.11.0
+ webpack@4.44.1
added 919 packages from 358 contributors in 71.123s
Removing intermediate container 279a1bd8a793
 ---> 5fa04a01f765
Successfully built 5fa04a01f765
Successfully tagged scratch3:12.16-alpine3.11
        
のようにやることでイメージビルドができます。

完成したイメージは以下で確認できます。

            
            $ docker images
REPOSITORY                       TAG                   IMAGE ID            CREATED             SIZE
tcnct/scratch3                   12.16-alpine3.11      5fa04a01f765        22 minutes ago      216MB
node                             12.16-alpine3.11      927d03058714        6 months ago        88.1MB
#以下略
        
webpack系のパッケージで容量が多少モリモリになっています。

この程度なら許容範囲内かと思います。

このイメージからコンテナ起動して、インタラクティブモードで入って、コンテナ停止、を以下で行ってみましょう。

            
            #👇コンテナを起動
$ docker-compose up -d
Creating network "scracth3dckr_default" with the default driver
Creating scracth3dckr_app_1 ...
Creating scracth3dckr_app_1 ... done
#👇appサービスにインタラクティブモードにbashから入る
$ docker-compose exec app bash
#👇コンテナ内で色々と作業
bash-5.0$ whoami
node
bash-5.0$ node --version
v12.16.1
bash-5.0$ npm --version
6.13.4
bash-5.0$ yarn --version
1.22.0
#👇作業が終わったらコンテナから抜ける
bash-5.0$ exit
exit
#👇コンテナを停止・破棄
$ docker-compose down
Stopping scracth3dckr_app_1 ... done
Removing scracth3dckr_app_1 ... done
Removing network scracth3dckr_default
        
基本的にはDockerコンテナ内に入ってのアプリ開発作業はこのような流れになると思います。

以上がnodejsおよびnpmパッケージを利用できるalpine-dockerコンテナの構築のお話です。

ただこれだけどまだ全然Scratch3.0自体がビルドできません。

以降の後半ではこのコンテナ内でScratch3.0のエクステンションを追加するためにライブラリ群を整備してみる内容を説明していきます。


Scratch3のソースビルド

ここの公式で述べられている手順を参考にScratch3のビルドを行っていきます。

現在の作業ルートディレクトリに以下のような内容の
package.jsonを新規で追加しておきます。

            
            {
  "name": "scratch3-gui-local",
  "version": "0.0.1",
  "scripts": {
    "start": "cd scratch-gui && yarn start",
    "build": "cd scratch-gui && yarn build",
    "prelink": "yarn link:vm && yarn link:p",
    "link:vm": "cd scratch-vm && yarn link",
    "link:p": "cd scratch-gui && yarn link scratch-vm"
  }
}
        
後述しますが、scratch-guiscratch-vmの異なる2つのプロジェクトを利用しています。

この場合、フォルダ切り替えながらの作業は地味に手間です。

そんなときには、ルートディレクトリからの便利に使えるスクリプトを前もってpackage.jsonに与えておきます。


scratch-guiとscratch-vm

まずはscratch-gui(メインアプリにあたるグラフィカルユーザーインターフェース)とscratch-vm(必須のライブラリ)を2つをプロジェクトごとクローンする必要があります。

            
            $ git clone --depth 1 https://github.com/llk/scratch-gui.git
Cloning into 'scratch-gui'...
remote: Enumerating objects: 1001, done.
remote: Counting objects: 100% (1001/1001), done.
remote: Compressing objects: 100% (966/966), done.
remote: Total 1001 (delta 61), reused 682 (delta 20), pack-reused 0
Receiving objects: 100% (1001/1001), 15.35 MiB | 99.00 KiB/s, done.
Resolving deltas: 100% (61/61), done.
        
そして、

            
            $ git clone --depth 1 https://github.com/llk/scratch-vm.git
Cloning into 'scratch-vm'...
remote: Enumerating objects: 488, done.
remote: Counting objects: 100% (488/488), done.
remote: Compressing objects: 100% (367/367), done.
remote: Total 488 (delta 119), reused 313 (delta 100), pack-reused 0
Receiving objects: 100% (488/488), 7.92 MiB | 125.00 KiB/s, done.
Resolving deltas: 100% (119/119), done.
        
で、2つのプロジェクトをローカルにクローンすることができます。

ひとまず2つのプロジェクトをダウンロードした段階でルートディレクトリからのファイル構造は、

            
            $ tree -L 2
.
├── Dockerfile
├── docker-compose.yml
├── package.json
├── scratch-gui
│   ├── LICENSE
│   ├── README.md
│   ├── TRADEMARK
│   ├── docs
│   ├── package-lock.json
│   ├── package.json
│   ├── prune-gh-pages.sh
│   ├── src
│   ├── static
│   ├── test
│   └── webpack.config.js
└── scratch-vm
    ├── LICENSE
    ├── README.md
    ├── TRADEMARK
    ├── docs
    ├── package-lock.json
    ├── package.json
    ├── src
    ├── test
    └── webpack.config.js
        
のようになっていると思います。

scratch-vm

先にscratch-vmから作業を始めます。

まずは
scratch-vmフォルダに移って、パッケージをインストールします。

            
            $ cd scratch-vm
$ yarn install
yarn install v1.22.0
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] Resolving packages...
warning nets > request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142
#...中略
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 87.16s.
        
インストールが正常完了したら、他のプロジェクトでも利用できるように、ここでライブラリリンクを作成しておきます。

            
            $ yarn link
yarn link v1.22.0
success Registered "scratch-vm".
info You can now run `yarn link "scratch-vm"` in the projects where you want to use this package and it will be used instead.
Done in 0.06s.
        

scratch-gui

続いてscratch-guiから作業します。

ますは、
scratch-guiフォルダに移り、先程のscratch-vm側のライブラリリンクを紐づけします。

            
            $ cd scratch-gui
$ yarn link scratch-vm
yarn link v1.22.0
success Using linked package for "scratch-vm".
Done in 0.06s.
        
ここでもパッケージインストールします。

            
            $ yarn install
yarn install v1.22.0
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] Resolving packages...
warning @babel/cli > chokidar@2.1.8: Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.
#...中略
[4/4] Building fresh packages...
success Saved lockfile.
Done in 89.77s.
        
では、このフォルダにとどまってscratch-guiを試しに起動させます。

            
            $ yarn start
webpack-dev-server
10% building 6/6 modules 0 activeℹ 「wds」: Project is running at http://0.0.0.0:8601/
ℹ 「wds」: webpack output is served from /
ℹ 「wds」: Content not from webpack is served from /usr/src/app/scratch-gui/build
65% building 581/631 modules 50 active ...sion-worker.js!/usr/src/app/scratch-gui/node_modules/babel-loader/lib/index.js??ref--4!/usr/src/app/scratch-gui/node_modules/scratch-vm/src/extension-support/extension-worker.js(node:189) DeprecationWarning: Tapable.apply is deprecated. Call apply on the plugin directly instead
ℹ 「wdm」: Hash: 969023fad960bd8371c2
Version: webpack 4.44.1
#中略
        [./node_modules/scratch-vm/src/util/log.js] 84 bytes {main} [built]
        [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 472 bytes {main} [built]
            + 5 hidden modules
ℹ 「wdm」: Compiled successfully.
        
これでwebpackのパッケージビルド後に、webpack-dev-serverでlocalhost側へSPAが送りだされます。

http://0.0.0.0:8601/にブラウザでアクセスすると、

合同会社タコスキングダム|蛸壺の技術ブログ

でScratch3.0が起動出来ていれば完了です。

Scratch3.0の起動

これはDockerコンテナ特有のお話で、インタラクティブモードからコンテナを抜けて、使用済みコンテナを破棄してしまうたびに、scratch-guiscratch-vm間で作成していたプロジェクト間のパッケージリンクが消えてしまいます。(コンテナを破棄しなければ良いだけですが...)

コンテナに入り直すたびに毎回フォルダに移って
yarn linkを打って回るのは面倒です。

なのでルートディレクトリから前もって用意していたスクリプトで対処します。

            
            $ yarn prelink # リンクの作成
$ yarn start   # ルートディレクトリから起動
        


まとめ

scratch3.0はオンライン版のSPAアプリで利用するのが主流になっています。

今回のようにオフラインでも利用できるようにする方法は、やり方のハードルも高く倦厭されがちかも知れません。

ただし、自作のエクステンションが作成できたり、nodeパッケージが利用できたりと、scratchのプログラミングにかなりの自由度が広がる点で大いにメリットがあると思います。


参考のサイト

Scratch Japan Wliki | Scratch 3.0の拡張機能を作ってみよう

Qiita | Scratch 3.0でオリジナルブロックをつくろう

Scratch 3.0 の Extension(拡張機能) を試してみた

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。