WindowsでHaxeビルド環境をDockerで作ってみた

# 用途
- Screeps:Arena というコーディングゲームで使うための外部ライブラリ作成用
- Hexaはコンパイル速いらしい。PHPとか出力言語も多彩

# 目次
- [環境](#環境)
- [ ディレクトリ構成](#ディレクトリ構成)
- [Dockerコンテナの準備](#Dockerコンテナの準備)
    - [Dockerfile](#Dockerfile)
    - [docker-composeファイル](#composeファイル)
    - [Dockerfile](#Dockerfile)
- [Haxeの準備](#Haxeの準備)
    - [テスト用コード](#テスト用コード)
    - [ビルド設定](#ビルド設定)
- [ライブラリビルド用の設定](#ライブラリビルド用の設定)

# 環境
- Windows 10 Home
- Docker Desktop

# ディレクトリ構成
```
├─Docker
│  │  docker-compose.yml
│  └─hexa-build
│          Dockerfile
│          entrypoint.sh
└─project
    │  build.hxml
    ├─bin
    │      lib.js
    └─src
        │  HelloWorld.hx
        └─foo
                BarLib.hx
```

# Dockerコンテナの準備
## Dockerfile
- ビルド環境は下記を参考。
    - ダウンロードのページにあるっていうね。
    - https://haxe.org/download/linux/

```Dockerfile
FROM node:slim

# haxe
RUN apt-get update
RUN apt-get install -y software-properties-common
#RUN add-apt-repository ppa:haxe/releases -y
#RUN apt-get update
RUN apt-get install haxe -y
RUN mkdir ~/haxelib && haxelib setup ~/haxelib
RUN haxelib install hxnodejs

COPY ./entrypoint.sh /entrypoint.sh
```

entrypoint.sh はビルドするだけ。
```entrypoint.sh
#!/bin/bash
cd /project
haxe build.hxml
```


### 躓きポイント
- Haxa公式だとapt-getのリポジトリ追加が必要みたいに書いてあったけどコメントアウトしてる部分はいらなかった。
    - 入れたら apt-update で `http://de.archive.ubuntu.com/ubuntu jammy InRelease` が見つからないエラーで止まっちゃう。
    - ちなみに、`software-properties-common` は先に `apt-get update` しないと見つからないエラーになる。
```
#0 1.467 Reading package lists...
#0 1.472 Building dependency tree...
#0 1.472 Reading state information...
#0 1.473 E: Unable to locate package software-properties-common
```
- oftware-properties-common がないと `haxelib` インストール時にエラーになる
```
RUN haxelib install hxnodejs:
#0 2.500 Error: Failed with error: SSL - No CA Chain is set, but required to operate
```

## composeファイル
後の拡張も考えてdocker-composeで作ってみる

```dockeer-compose.yml
version: '3'
services:
  haxe-build:
    build:
      context: ./hexa-build
      dockerfile: Dockerfile
    volumes:
      - ../project:/project
    #command: /bin/bash
    #tty: true
    entrypoint: /entrypoint.sh
    container_name: haxe-build
```

### 躓きポイント
うまくいかない時はentrypointをコメントアウトして↑のコメント外してコンテナの中に入って試してた。
こうするとコンテナが終了せずに持続する。
よく tty だけつければって見るけど command も必要。（常駐するプロセスが必要）
```docker-compose.yml
    command: /bin/bash
    tty: true
    #entrypoint: /entrypoint.sh
```

# Haxeの準備

## テスト用コード
外部ライブラリを用意したいけどビルドサンプルのためにHalloWorldで試す
```HellowWorld.hx
class HelloWorld {
    static public function main():Void {
        // Single line comment
        trace("Hello World");
    }
}
```
- ファイル名はクラス名と同じにする。（HelloWorld.hx）
- ディレクトリは src の下に置く。
- うまくいかないときはサブディレクトリとか作らずに、１つのディレクトリでとりあえずビルドできることを目指した方がいい

## ビルド設定
```build.hxml
-cp src
-main HelloWorld 
-js bin/test.js
```
- https://haxe.org/manual/compiler-usage.html を参考
- うまくいけば bin/test.js が出力される

### 躓きポイント
- クラスパスは `-cp`。 `--class-path, -p` だと指定できなかった
    - 見つからないと`Type not found : ~~` ってエラーになる。
- main がないとコマンドUsageが表示される。
   - 必要なオプションがないと--helpが出る。（それはそう）

# ライブラリビルド用の設定
https://code.haxe.org/category/compilation/compiling-libraries-without-main-class.html を参考

#### サンプルコード
※[2022-04-22追記](#外部ライブラリとしての出力方法)  
```BarLib.hx
package foo;

class BarLib {
  public function new()  {}

  public function test() {
    return "Hello from BarLib!";
  }
}
```
#### ビルド設定
```build.hxml
-cp src
-cp src/foo
foo.BarLib
-js bin/lib.js
```

### 躓きポイント
- クラスパスのサブディレクトリは都度 `-cp` で指定する必要があるっぽい
- main は不要。代わりに`パッケージ.クラス名`を都度指定する
- ↑の記載順で書かないと動かなかった。

# 追記 2022-04-22
## es-6 フォーマットの出力ができる
`-D js-es6` 指定すればいいみたい（hxnodejs用）
```build.hxml
-lib hxnodejs
-D js-es=6
```
## 外部ライブラリとしての出力方法
- `@:expose` をつければいいらしい
   - 出力結果は `require()` で使う想定みたい
   - importでどうやって読み込めばいいのかわからない……
- 下記参照
    - https://haxe.org/manual/target-javascript-expose.html
    - https://github.com/HaxeFoundation/hxnodejs
 ```BarLib.hx
@:expose("foo.BarLib")
class BarLib {
  function new() {
  }
  public function test():String {
    return "Hello from BarLib!";
  }
}
```
出力結果
export がつけば import でも使えそうなのになあぁあ～～～
```outout.js
// Generated by Haxe 4.1.5
var $hx_exports = typeof exports != "undefined" ? exports : typeof window != "undefined" ? window : typeof self != "undefined" ? self : this;
(function ($global) { "use strict";
$hx_exports["foo"] = $hx_exports["foo"] || {};
class foo_BarLib {
	constructor() {
	}
	test() {
		return "Hello from BarLib!";
	}
}
$hx_exports["foo"]["BarLib"] = foo_BarLib;
class haxe_iterators_ArrayIterator {
	constructor(array) {
		this.current = 0;
		this.array = array;
	}
	hasNext() {
		return this.current < this.array.length;
	}
	next() {
		return this.array[this.current++];
	}
}
})({});
var foo = $hx_exports["foo"];
```

# 余談
## WindowsのDockerコンテナ使ってVSCodeでhadlint使おうとしたけど挫折した
https://qiita.com/uokada/items/5ed72b2998ec07ca92fa を参考。
Powershellでスクリプトを用意してみた。
```powershell
docker run --rm -i hadolint/hadolint:latest hadolint - --no-color $args
```
VSCodeプラグインの設定で実行ファイルのパスにスクリプト設定してみたけどうまく動かなかった。
Set-Aliasも試してみたけどダメだった。（PowerShellの扱いに慣れてないだけかもしらん）