KotlinをNode.jsに変換してWebサーバーを作るメモ #teratail_kt


KotlinがJSに変換できるとのことだったので、調べたら出て来た[Your first Node.js app with Kotlin](https://medium.com/@Miqubel/your-first-node-js-app-with-kotlin-30e07baa0bf7)の記事を追ってやってみました。

![](https://i.gyazo.com/086cc1d65637b31af79490b44bf750a4.png)


ちなみに[CLIとVSCodeでKotlin開発を始めてみるメモ](https://qiita.com/n0bisuke/items/4acb2d8be7a82d80a7c9)に引き続きVSCodeとCLIで進めていきます。

## 環境

* macOS Sierra
* Kotlin 1.1.50
* Gradle v4.2
* Node.js v8.4.0

## Gradleのインストール

GradleはNode.jsでいうnpmみたいなイメージです。
依存関係解決してくれます。

インストールはhomebrewでいけます。

```
$ brew install gradle
```

```
$ gradle -v

------------------------------------------------------------
Gradle 4.2
------------------------------------------------------------

Build time:   2017-09-20 14:48:23 UTC
Revision:     5ba503cc17748671c83ce35d7da1cffd6e24dfbd

Groovy:       2.4.11
Ant:          Apache Ant(TM) version 1.9.6 compiled on June 29 2015
JVM:          1.8.0_101 (Oracle Corporation 25.101-b13)
OS:           Mac OS X 10.12.6 x86_64
```

無事にインストールできました。

## プロジェクトを作っていく

任意フォルダを作って移動

```
$ mkdir myjsapp
$ cd myjsapp
```

Node.jsプロジェクトの初期化

```
$ npm init -y
```

`npm init`で`package-lock.json`と`package.json`が出来上がります。

次に必要なモジュールをインストール

```
$ npm i --save kotlin express
```

インストールされると`node_modules`フォルダができます。

```
$ ls
node_modules      package-lock.json package.json
```

この階層に`build.gradle`というファイルを作成して次の内容を書き込みます。

```build.gradle
group 'node-example'
version '1.0-SNAPSHOT'

buildscript {
  ext.kotlin_version = '1.1.1'
    repositories {
      mavenCentral()
    }
  dependencies {
    classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
  }
}

apply plugin: 'kotlin2js'

repositories {
  mavenCentral()
}

dependencies {
  compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

compileKotlin2Js.kotlinOptions {
  moduleKind = "commonjs"
  outputFile = "node/index.js"
}
```

次に同じ階層に`src`フォルダを作成し、その中に`main`フォルダ、さらにその中に`kotlin`フォルダを作り、その中に`Main.kt`を作成しましょう。

```src/main/kotlin/Main.kt
external fun require(module:String):dynamic

fun main(args: Array<String>) {
    println("Hello JavaScript!")

    val express = require("express")
    val app = express()

    app.get("/", { req, res ->
        res.type("text/plain")
        res.send("i am a beautiful butterfly")
    })

    app.listen(3000, {
        println("Listening on port 3000")
    })
}
```

これで準備完了です。

普段Node.jsを書いている人なら`val express = require("express")`の箇所からも分かる通り`express`を使ったWebサーバーになります。

現状ではこんな感じのフォルダ構成になっています。

![](https://i.gyazo.com/c1e63330beb89a68cae5279f4f15d49e.png)

`package.json`や`build.gradle`ファイルがあるルートの階層で`gradle build`コマンドを実行しましょう。

```
$ gradle build
```

```
> Configure project :
Gradle now uses separate output directories for each JVM language, but thisbuild assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0
        at build_b5jf4f0juy83k80loi4m0mzgo.run(/Users/n0bisuke/dotstudio/2_events/20170930_kotlin/myjsapp/build.gradle:14)
        (Run with --stacktrace to get the full stack trace of this deprecation warning.)

w: /Users/n0bisuke/dotstudio/2_events/20170930_kotlin/myjsapp/src/main/kotli
n/Main.kt: (9, 20): Parameter 'req' is never used

BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed
```

するとビルドが行われ、`build`フォルダと`node`フォルダが出来上がります。

## 実行

`node`フォルダ内の`index.js`を指定します。

```
$ node node/index.js

Hello JavaScript!
Listening on port 3000
```

これで http://localhost:3000 にアクセスするとサーバーが立ち上がっていることが確認できます。

`i am a beautiful butterfly`って表示されましたか?

## 変換されたindex.js

変換後の`index.js`です

```index.js
(function (_, Kotlin) {
  'use strict';
  var println = Kotlin.kotlin.io.println_s8jyv4$;
  function main$lambda(req, res) {
    res.type('text/plain');
    return res.send('i am a beautiful butterfly');
  }
  function main$lambda_0() {
    println('Listening on port 3000');
  }
  function main(args) {
    println('Hello JavaScript!');
    var express = require('express');
    var app = express();
    app.get('/', main$lambda);
    app.listen(3000, main$lambda_0);
  }
  _.main_kand9s$ = main;
  Kotlin.defineModule('index', _);
  main([]);
  return _;
}(module.exports, require('kotlin')));
```

## 感想

最初から最後までCLIとVSCodeだけで書けました。

![](https://i.gyazo.com/027b435efdb72c31a1f6800f05e9cb1a.png)

調べているとGradleやMavenのようなツールが当たり前のように出てくるけど、普段使わないので調べ方で戸惑いました。

この仕組みが実用的かどうかはまだ何とも言えない段階な気もするので、とりあえずはこんなこともできるよってくらいの認識で良さそうです。

## 参考

* [Your first Node.js app with Kotlin](https://medium.com/@Miqubel/your-first-node-js-app-with-kotlin-30e07baa0bf7)
* [Kotlin の JavaScript サポートを試す](http://kitak.hatenablog.jp/entry/2017/06/20/153212)