のぶLab.

流しのソフトウェアエンジニアの雑記帳. Android, Scala, Clojure, Ruby on Railsなど

Scalajs + React + Electronでhello world

scala, sbt未インストール状態からScalaJS, Reactを使ってElectronでHello worldするまで

環境はMacOS X Yosemite

ScalaJSとは

AltJS Scalaで書いたコードがJSに変換される

http://www.scala-js.org/doc/tutorial.html

sbtとは

Scala向けのpackage managerみたいなやつ

Scala, sbtをインストール

homebrew などでインストール

$ brew install scala
$ brew install sbt

Project作成

$ mkdir sample
$ cd sample
$ touch build.sbt
$ mkdir project
$ touch project/plugins.sbt
$ touch project/build.properties
$ sbt

ScalaJSのTutorialにそってHelloworldする

http://www.scala-js.org/doc/tutorial.html

このTutorialの'Integrating with HTML'まで

これをベースにこの後scalajs-reactを導入し、Electronで動くようにする

scalajs-reactの導入

github.com

こいつを導入します

build.sbtを編集

build.sbtにscalajs-reactの依存関係を追加

enablePlugins(ScalaJSPlugin)

name := "Scala.js Tutorial"

scalaVersion := "2.11.6"

libraryDependencies += "org.scala-js" %%% "scalajs-dom" % "0.8.0"

libraryDependencies += "com.github.japgolly.scalajs-react" %%% "core" % "0.9.0"

libraryDependencies += "com.github.japgolly.scalajs-react" %%% "extra" % "0.9.0"


jsDependencies +=
  "org.webjars" % "react" % "0.12.2" / "react-with-addons.js" commonJSName "React"

target/index.htmlを編集

reactを導入することでJSライブラリにも依存関係が発生するのでindex.htmlも変更します

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>ScalaJS Tutorial</title>
</head>
<body>
    <script type="text/javascript" src="./scala-2.11/scala-js-tutorial-jsdeps.js"></script>
    <script type="text/javascript" src="./scala-2.11/scala-js-tutorial-fastopt.js"></script>
    <script type="text/javascript">
      tutorial.webapp.TutorialApp().main();
    </script>
</body>
</html>

TutorialApp.scalaを編集

reactを使って'hello world'の出力を行います

package tutorial.webapp

import scala.scalajs.js.JSApp
import org.scalajs.dom
import dom.document
import japgolly.scalajs.react.{React, ReactComponentB}
import japgolly.scalajs.react.vdom.prefix_<^._


object TutorialApp extends JSApp {

  def main(): Unit = {
    val hello =
      ReactComponentB[Unit]("Hello world")
        .render(_ => <.div("Hello world"))
        .buildU

    React.render(hello(), document.body)
  }
}

一旦この状態でブラウザで確認してみて'Hello world'が表示されていたら次に進む

Electronアプリ化

基本的にはElectronのquick-startで作成しているファイルをtarget/ 配下に作ります

electron/quick-start.md at master · atom/electron · GitHub

npm init
npm install --save electron-prebuilt

target/ 配下にmain.jsを作成

$ touch target/main.js
var app = require('app');  // Module to control application life.
var BrowserWindow = require('browser-window');  // Module to create native browser window.

// Report crashes to our server.
require('crash-reporter').start();

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html');

  // Open the devtools.
  mainWindow.openDevTools();

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});

この状態で

$ electron target/main.js

Electronアプリが起動して'Hello world'が表示されたらOK