ScratchX の Extension をローカルで開発する環境を整える

## ScratchX ?

- ScratchX には Scratch の拡張ブロック (Extension) を作る機能がある(まだベータ)。
  - 簡単に言うと Scratch に自分で作った(JS で書いた)ブロックを追加できる
  - ソフトウェアだけで閉じたブロックや Arduino とかのハードウェアに繋がるブロックも作れる

詳しくは https://github.com/LLK/scratchx/wiki を参照。

## 今回やること

ScratchX の Extension の JavaScript スクリプトはどこかのサーバーに置いて ScratchX に読み込ませる必要がある。

公式のガイド (https://github.com/LLK/scratchx/wiki) によると Github Pages を使うことが推奨されている。

しかし、少しプログラムを変更する度に毎回 Github に push するのは面倒なのでもっと簡単に開発する方法が欲しい。

幸いなことに ScratchX は localhost からのスクリプトの読み込みができるため、自分のマシン上にサーバーを立ててそこから読み込ませるようにする。

今回はその環境を作って簡単なブロックを作るところまでやる。

コマンドラインを使う所が出てきますが、詳しく分からなくても大丈夫なように基本的にコピペでできるようにします。

## 環境を構築した環境

- MacBook Pro (Retina, 13-inch、Early 2015)
- OS X Yosemite 10.10.5


## 必要なもの

- node
  - JavaScript を動かす環境
  - homebrew の環境下なら `brew install node` でインストールできる
  - それ以外の場合は `node インストール mac` とかでググッてインストールする
- エディタ
  - なんでも構いませんが [atom](https://atom.io/) が最近の流行りっぽいです
  - トップページの動画が SF 好きには好評なやつです

## サンプルとして作る Extension 

今回はローカルで開発する環境を作るのがメインなので難しい Extension は作らず、ログを出力するだけのものを作ります。

完成のイメージとしては指定した文字をアラートで出す感じです。

アラートの代わりに `console.log` を使うことでデベロッパーツールをログを出すこともできます。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/fda2a89f-8120-f070-ae48-252b8b028257.png)


## 実際に作る

前置きが長くなりましたが実際に作っていきましょう。

### プロジェクトのフォルダを作る

まずはプロジェクトのフォルダを作ります。

好きなところに `scratchx_log` というフォルダを作りましょう。

そして、その中に `src` というフォルダを作りましょう。

`src` の中にソースコードを入れていきます(source code の src です)。 

こんな感じになっていれば大丈夫です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/ca3224ec-6b4f-be82-67de-61ee2afd95c8.png)

### crossdomain.xml を作る

`crossdomain.xml` というものを作ります。

詳しい説明は省きますが ScratchX に自分で作った Extension の JavaScript を読みこませるために必要なファイルです。

内容については何も分からなくて大丈夫なので以下の xml をコピペして `src` フォルダの中に `crossdomain.xml` という名前で保存しましょう。

```xml:crossdomain.xml
<cross-domain-policy xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.adobe.com/xml/schemas/PolicyFile.xsd">
  <site-control permitted-cross-domain-policies="master-only"/>
  <allow-access-from domain="scratchx.org"/>
  <allow-access-from domain="llk.github.io"/>
</cross-domain-policy>
```

以下の様な感じになっていれば大丈夫です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/d87b827e-62ec-3fe6-c10a-61166d300036.png)

### log_extension.js を作る

次に Extension の JavaScript ファイルを作ります。

ここに書いた内容が Scratch に表示されます。

ちょっと長いですが、これもエディタで `src` フォルダの中に `log_extension.js` という名前で保存します。

面倒だったらコピペしてみてください。

```js:log_extension.js
(function(ext) {

  // コメントは補足の説明なので書かなくてもいいです

  // Extension が終了するときに呼ばれる
  // 今は特に何もしない
  ext._shutdown = function() {};

  // Extension の状態を返す
  // デバイスが繋がっていないときにはエラーを返したりする
  // ---
  // 返す値, 表示される色, 意味
  //      0,          red, error
  //      1,       yellow, not ready
  //      2,        green, ready
  // ---
  // 今回はデバイスなどは使用しないので常に準備完了
  // ということで 2 を返します。
  ext._getStatus = function() {
    return {status: 2, msg: 'Ready'};
  };

  // この関数がブロック処理になります。
  ext.log = function(str) {
    // ログを出力するだけ
    alert(str);
  };

  // ブロックをどういう風に表示するかを書きます
  // ここの書き方は結構難しいので今は説明しません
  var descriptor = {
    blocks: [
      [' ', 'log %s', 'log', 'sample log']
    ]
  };

  // Scratch に作ったブロックを登録します
  ScratchExtensions.register('Log Extension', descriptor, ext);
})({});
```

こんな感じになっていれば大丈夫です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/5f7536b8-eefc-35d4-a434-c77d4c1af2b9.png)

これで Extension の開発は完了です。

次からは作った Extension を ScratchX に読み込ませる作業をしていきます。

### ローカルサーバーを起動する

ここから少し難しい作業が続きますが、基本的にはコピペしていくだけなので頑張ってみてください。

まずは `package.json` というファイルを作ります。

これは nodejs という環境で使う設定ファイルのようなものです。

今回はコレにローカルサーバーの設定を書き簡単にサーバーを立ち上げられるようにします。

内容に関しては分からなくて大丈夫なので以下のソースコードをコピペして `scratchx_log` フォルダに `package.json` という名前で保存します(`src` の中ではないので注意)。

```js:package.json
{
  "name": "scratchx_log",
  "version": "1.0.0",
  "description": "ScratchX のサンプルプロジェクトです。",
  "main": "index.js",
  "scripts": {
    "start": "http-server -c-1 src",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "MIT",
  "dependencies": {
    "http-server": "^0.9.0"
  }
}
```

以下の様な感じになっていればおっけーです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/2577c18c-555a-5303-1de9-b69d36e86fce.png)

次はローカルサーバーを立ち上げます。

`terminal` で `scratchx_log` のフォルダまで移動します。

ターミナルでの作業に慣れていないと分からないかもしれないので、分からない人は誰か分かる人に聞いてください。

`cd <scratchx_log へのパス>` というコマンドを使います。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/66bdf893-2357-c8cc-42e4-8a80da56e731.png)

移動したら `npm install` というコマンドを実行します。

これによってサーバーの起動に必要なファイルがダウンロードされます。

その後 `npm start` というコマンドを実行してサーバーを起動します。

この2つのコマンドを実行すると以下の様な画面になると思います。

何かエラーが出る場合は nodejs が分かる人に聞いてください。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/01473877-2b06-6053-6a86-27dba3ac55d8.png)

これでローカルサーバーの起動は完了です。

サーバーを終了するときはキーボードの `Ctrl` と `c` を同時に押します。

サーバーを起動するときは `npm start` と実行します。

### ScratchX で使ってみる 

ここまで非常に長い道のりでしたが、これでようやく ScratchX で使うことができます。

まずはサーバーが正しく立ち上がっていることを確認するために `http://localhost:8080/log_extension.js`をブラウザ (Google Chrome)で開いてみてください。

`log_extension.js` に書いた内容が表示されればおっけーです。

では ScratchX で使ってみましょう。

`http://scratchx.org/?url=http://localhost:8080/log_extension.js` をブラウザで開くだけで使えます(簡単!)。

すると以下の様な画面が開くので右側の `I understand, continue` という緑色のボタンを押します。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/8f3906d4-3dd4-91db-a495-1373e3f2b3ba.png)

ボタンを押すと以下の様な見覚えのある画面になります。

`More Blocks` のところにある `Log Extension` のところにあるのが今回作った Extension です。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/4f91937f-ef3d-6ac3-9eb3-110ea4f006bf.png)

早速こんな感じのブロックを組んでみましょう。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/c7bdf60a-d445-5aa4-b9f4-9a9392e7d319.png)

その状態で緑の旗を押してプログラムを実行すると下のような感じにアラートが表示されるはずです。

![image](https://qiita-image-store.s3.amazonaws.com/0/17704/fda2a89f-8120-f070-ae48-252b8b028257.png)


これで ScratchX にローカルに立てたサーバーから Extension の JavaScript ファイルを読み込ませることができました。

これを基本として色々開発することができます。

## まとめ

Github とかを使わずにローカルの環境だけで ScratchX に Extension を読みこませる事ができました。

まだまだ ScratchX はベータ版なので試すだけでも面倒ですが、改善されていくのを楽しみにしたいと思います。

今後は様々なブロックを作ったり、 Github に公開したりする方法について書いていきたいと思います。

Arduino などのハードウェアに接続したり、外部の Web サービスとの連携したりする機能についても書いていきたいです。