ちょっと前に Kotlin Multiplatform 1.9.22 Kotlin/JS Hello, World! を書いたのですが、2.0.0 が出たのでやりなおしです。
このあたりの https://kotlinlang.org/docs/js-project-setup.html 話です。
$ java --version
openjdk version "17.0.11" 2024-04-16
$ gradle --version
Gradle 8.5
$ npm --version
10.4.0
$ node --version
v18.17.1
プロジェクトディレクトリを作成:
$ mkdir hello
$ cd hello
$ touch build.gradle.kts
build.gradle.kts の内容:
plugins {
kotlin("multiplatform") version "2.0.0"
}
version = "0.1"
repositories {
mavenCentral()
}
kotlin {
js {
nodejs()
binaries.library()
}
}
続いて Main.kt の用意:
$ mkdir -p src/commonMain/kotlin/
$ touch src/commonMain/kotlin/Main.kt
Main.kt を配置するパスは src/commonMain/kotlin の代わりに src/jsMain/kotlin にしても問題ありませんでした。
Main.kt にコードを記述。
@ExperimentalJsExport
@JsExport
fun sayHello(name: String): String {
return "Hello, ${name}!"
}
@ExperimentalJsExport アノテーションをつけないでビルドするとビルド時になんやかんやいわれるのでつけた方が良さそう(つけなくても作動するにはするようですが)。
ここで、一度 build して問題がないか確かめます。
$ gradle build
ビルドできたら、 続いて gradle wrapper しておきます。
$ gradle wrapper
これ以後は gradle コマンドの代わりに ./gradlew を使います。
gradlew が機能するか確かめるために clean と build を実行。
$ ./gradlew clean build
ビルドした hello.js がどこに生成されたか確認。
$ find . -name hello.js
./build/js/packages/hello/kotlin/hello.js
./build/dist/js/productionLibrary/hello.js
./build/compileSync/js/main/productionLibrary/kotlin/hello.js
よくわからないのだが、たぶん、build/js/packages/hello/kotlin/hello.js を使えばいいのではないか?
hello.js は次の内容で生成されています。
(function (root, factory) {
if (typeof define === 'function' && define.amd)
define(['exports'], factory);
else if (typeof exports === 'object')
factory(module.exports);
else
root.hello = factory(typeof hello === 'undefined' ? {} : hello);
}(globalThis, function (_) {
'use strict';
//region block: pre-declaration
//endregion
function sayHello(name) {
return 'Hello, ' + name + '!';
}
//region block: exports
function $jsExportAll$(_) {
_.sayHello = sayHello;
}
$jsExportAll$(_);
//endregion
return _;
}));
//# sourceMappingURL=hello.js.map
たしかに sayHello 関数が入っています。よさそう。
このライブラリの sayHello 関数を Javascript (Node.js) から使うには、次のようにします。
$ cd build/js
$ touch main.js
./build ディレクトリは ./gradlew clean したら消えるので注意しましょう。必要なら build/js ごとどこかにコピーして作業すべきかもしれません。
まず CommonJS 方式で使ってみます。
main.js:
const hello = require("hello");
console.log(hello);
console.log(hello.sayHello("Pika"));
node main.js として実行して作動を確かめます。
$ node main.js
{ sayHello: [Function: sayHello] }
Hello, Pika!
うまくいきました。
ESModule としても使えます。
$ touch main.mjs
main.mjs に次のコードを書きます。
import hello from "hello";
console.log(hello);
console.log(hello.sayHello("Pika"));
node main.mjs として実行すれば先ほどと同じ結果が得られます。
これで sayHello するライブラリはできました。
しかし、現状のままでは main.js (または main.mjs) を動かすためには、 ./node_modules/ , ./packages/ を全部コピーする必要があります。
そこで webpack を使って このライブラリを一つのファイルにまとめます。
./gradlew build すると生成される ./build/js/ ディレクトリは package.json があるのを見てもわかるようにすでに Node.js のプロジェクトになっています。 webpack してファイルを一つにまとめたいので、webpack コマンドが使えるように webpack と webpack-cli を入れます。
$ npm install webpack@5.92.0 --save-dev
$ npm install webpack-cli@5.1.4 --save-dev
続いて webpack.config.js を用意します。
const path = require('path');
module.exports = {
mode: 'production',
entry: './packages/hello/kotlin/hello.js',
output: {
library: 'hello',
libraryTarget: 'commonjs',
path: __dirname,
filename: 'hellolib.js'
}
}
そして、webpack します。
$ npx webpack --config webpack.config.js
これでカレントディレクトリに hellolib.js が生成されます。
webpack.config.js の module.exports.output.filename に指定したファイル名で生成される。
index.js を用意して次のように記述します。
const hello = require("./hellolib.js").hello;
console.log(hello);
console.log(hello.sayHello("Pika"));
実行してみます。
$ node index.js
{ sayHello: [Function: o] }
Hello, Pika!
先ほどと同じように作動しました。
これで index.js と hellolib.js の2つのファイルだけを配布すれば このライブラリを作動させることができるようになりました。
以上です。