KotlinJS x ReactNativeにトライしてみた
前回でKotlinJSの使い方がチョットだけわかったので、ReactNativeで動くようにしてみたいと思います。
プロジェクト作成。
Intellij ideaで進めていきます。
KotlinJSプロジェクトを作ります。
次のそのプロジェクトのrootでReactNativeのプロジェクトを作ります。
react-native init rn
とりあえず図のような構成にします。
コンパイル結果のディレクトリを調整する
Project Structure -> Project Settings -> Projectを開きます。
Project compiler outputをReactNativeプロジェクトのnode_modulesにします
変更後
次にProject Structure -> Project Settings -> Modulesを開きます。
図のCompiler outputを作成したReactNativeプロジェクトのnode_modulesに変更します。
変更後
次に、Preferences -> Build, Execution ... -> Compiler -> Kotlin Compilerを開きます。
前回もありましたが、Destination directoryとModule kindを以下のように変更します。
これでプロジェクトの設定は完了です。
ReactNativeでHelloWorld
では、ハロワしましょう。
index.jsはReact Nativeが直接参照しているので変更してはいけません。
とりあえずはrnディレクトリにあるApp.jsを変更して今回目標とするハロワのコードを書いてみましょう。
App.js
import React from 'react'; import { Text, View, } from 'react-native'; module.exports = () => <View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}> <Text>Hello World</Text> </View>;
これをiPhoneSimulatorで確認します。
react-native run-ios
目標はこんな感じです。
App.ktを作成
src以下にApp.ktファイルを作成します
コンパイルが通る程度に適当にApp.jsっぽい感じに書いてみましょう
import kotlin.js.json @JsModule("react") external object React { class Component fun createElement(element:Component, props: dynamic, children: dynamic) } @JsModule("react-native") external object ReactNative { val View: React.Component val Text: React.Component } fun App():dynamic = React.createElement( ReactNative.View, json(Pair("style", json( Pair("flex", 1), Pair("alignItems", "center"), Pair("justifyContent", "center") ))), React.createElement(ReactNative.Text, null, "Hello World"));
JSXでは書けないのでReact.createElementで書きます。
json
これはKotlinJSの機能でJavaScriptのJSONに変換できる機能です。
json - Kotlin Programming Language
以下がコンパイル結果です
(function (_, Kotlin, $module$react, $module$react_native) { 'use strict'; var Pair = Kotlin.kotlin.Pair; var json = Kotlin.kotlin.js.json_pyyo18$; function App() { return $module$react.createElement($module$react_native.View, json([new Pair('style', json([new Pair('flex', 1), new Pair('alignItems', 'center'), new Pair('justifyContent', 'center')]))]), $module$react.createElement($module$react_native.Text, null, 'Hello World')); } _.App = App; Kotlin.defineModule('ReactNativeKotlin', _); return _; }(module.exports, require('kotlin'), require('react'), require('react-native')));
コンパイル結果みるとイケそうな感じ
index.jsを少し変更します。
import { AppRegistry } from 'react-native'; import { App } from 'ReactNativeKotlin'; AppRegistry.registerComponent('rn', () => App);
実行
...
...
...
(あれ、読み込みが遅い…)
...
...
駄目だったか…
原因を探す
とりあえずbundleだけしてみましょう。
% react-native bundle --entry-file index.js --bundle-output ./ --dev false --platform ios Scanning folders for symlinks in /Users/Ryohlan/dev/kotlin/ReactNativeKotlin/rn/node_modules (15ms) Scanning folders for symlinks in /Users/Ryohlan/dev/kotlin/ReactNativeKotlin/rn/node_modules (14ms) Loading dependency graph, done.
...
...
bundleも終わらない。
kotlin.jsがbundle出来ない
コンパイル結果を色々いじって見た結果、kotlin.jsをrequireするとbundleが上手く行きません。
ログにタイムアウトが出てたのでmetro-bundlerのタイムアウト時間を伸ばしてみたけど駄目でした。
とりあえず、kotlin.jsからコンパイル結果で使っているものを抜粋して動かしてみます。
function Pair(first, second) { this.first = first; this.second = second; } Pair.prototype.toString = function () { return '(' + this.first + ', ' + this.second + ')'; }; Pair.prototype.component1 = function () { return this.first; }; Pair.prototype.component2 = function () { return this.second; }; function json(pairs) { var tmp$; var res = {}; for (tmp$ = 0; tmp$ !== pairs.length; ++tmp$) { var tmp$_0 = pairs[tmp$]; var name = tmp$_0.component1(), value = tmp$_0.component2(); res[name] = value; } return res; } var Kotlin = { defineModule: function(a, b) {}, kotlin: { Pair: Pair, js: { json_pyyo18$: json, } } }; (function (_, Kotlin, $module$react, $module$react_native) { 'use strict'; var Pair = Kotlin.kotlin.Pair; var json = Kotlin.kotlin.js.json_pyyo18$; function App() { return $module$react.createElement($module$react_native.View, json([new Pair('style', json([new Pair('flex', 1), new Pair('alignItems', 'center'), new Pair('justifyContent', 'center')]))]), $module$react.createElement($module$react_native.Text, null, 'Hello World')); } _.App = App; Kotlin.defineModule('ReactNativeKotlin', _); return _; }(module.exports, Kotlin, require('react'), require('react-native')));
ちゃんと表示されました。
やはりkotlin.jsの何かが問題なようです。(37000行あるので全部見れてません…)
うーむ、いいところまで行った気がしたんですがね。
まとめ
現状だと普通に動かすのは無理のようです。
kotlin.jsはKotlinの機能をjsに置き換える処理が書かれているので無くすことは出来ないので、修正されるかReactNative用の何かが出るまで待つしかないですかね。
まぁReactNativeでKotlinJS使いたいって要望無さそうですが…
と思ったらいるっぽい。
Use Kotlin with npm, webpack and react | Kotlin Blog