Edited at

Scala.js で CommonJSモジュールを使う

Scala.jsでCommonJS形式のモジュールを使ってみる。ES modulesでないのは、単に他の設定が不要でNodeJSが使えるからである。ES modulesでも大差なく使えるでしょう。


読み込みするファイルを用意

console.logを吐くだけのものを二種類用意した。


foo.js

module.exports = (obj) => console.log(obj);



bar.js

module.exports = {

bar: (obj) => console.log(obj)
};

これらのファイルはNODE_PATH通さなくてもいいようにnode_modulesに置いて使う。

https://github.com/eiel-sample-code/scalajs-use-cjs/tree/master/node_modules


設定

sbtの設定で必要なのはscalaJSLinkerConfig.moduleKindの設定。

この設定をしておくことで、CommonJS形式でコードが出力されるので、NodeJSで実行できる。

scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) },

https://github.com/eiel-sample-code/scalajs-use-cjs/blob/master/build.sbt#L12


補足

scalaJSLinkerConfig.moduleKind

デフォルトはNoModuleESModuleも用意されている。

https://github.com/scala-js/scala-js/blob/v0.6.26/tools/shared/src/main/scala/org/scalajs/core/tools/linker/backend/ModuleKind.scala#L18-L54


Facadeを用意する

Scalaから使えるようにFacadeを定義する。

平たく言うと、使おうとするjsのインターフェースをかく。

import scala.scalajs.js

import scala.scalajs.js.annotation.JSImport

@js.native
@JSImport("foo.js", JSImport.Default)
object Foo extends js.Object {
def apply(obj: js.Any): Unit = js.native
}

import scala.scalajs.js

import scala.scalajs.js.annotation.JSImport

@js.native
@JSImport("bar.js", JSImport.Namespace)
object Bar extends js.Object {
def bar(obj: js.Any): Unit = js.native
}

このobjectを利用すればrequireが生成されるJSに挿入される感じ。

@JSImportの部分が肝でここに基づいてコードが生成される。

foo.jsはdefault exportしているので、JSImport.Defaultにしている。

applyメソッドが自動的にマッピングされる模様。ソースは確認していない。

bar.jsはどちらでもよいがNamespaceにした。

https://github.com/eiel-sample-code/scalajs-use-cjs/blob/master/src/main/scala/Main.scala#L11-L21


補足

https://github.com/scala-js/scala-js/blob/v0.6.26/library/src/main/scala/scala/scalajs/js/annotation/JSImport.scala#L82

JSImport.Default"default"になってるだけ。


使う

object Main extends App {

Foo("Hello, Foo")
Bar.bar("Hello, Bar")
}

https://github.com/eiel-sample-code/scalajs-use-cjs/blob/master/src/main/scala/Main.scala#L4-L7


結果

$ sbt run

Hello, Foo
Hello, Bar
$ sbt fastOptJS fullOptJS
$ node target/scala-2.12/scalajs-use-cjs-fastopt.js
Hello, Foo
Hello, Bar
$ node target/scala-2.12/scalajs-use-cjs-opt.js
Hello, Foo
Hello, Bar

$ grep require target/scala-2.12/scalajs-use-cjs-fastopt.js

var $i_bar$002ejs = require("bar.js");
var $i_foo$002ejs = require("foo.js");
$ grep 002ejs target/scala-2.12/scalajs-use-cjs-fastopt.js
var $i_bar$002ejs = require("bar.js");
var $i_foo$002ejs = require("foo.js");
$moduleDefault($i_foo$002ejs)("Hello, Foo");
$i_bar$002ejs.bar("Hello, Bar")


参考