Scala.jsでCommonJS形式のモジュールを使ってみる。ES modulesでないのは、単に他の設定が不要でNodeJSが使えるからである。ES modulesでも大差なく使えるでしょう。
読み込みするファイルを用意
console.logを吐くだけのものを二種類用意した。
module.exports = (obj) => console.log(obj);
module.exports = {
bar: (obj) => console.log(obj)
};
これらのファイルはNODE_PATH通さなくてもいいようにnode_modules
に置いて使う。
設定
sbtの設定で必要なのはscalaJSLinkerConfig.moduleKind
の設定。
この設定をしておくことで、CommonJS形式でコードが出力されるので、NodeJSで実行できる。
scalaJSLinkerConfig ~= { _.withModuleKind(ModuleKind.CommonJSModule) },
補足
scalaJSLinkerConfig.moduleKind
デフォルトはNoModule
。ESModule
も用意されている。
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/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")
}
結果
$ 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")
参考
- 今回のコード
- Scala.js - Emitting a JavaScript module