Showing posts with label kotlin. Show all posts
Showing posts with label kotlin. Show all posts

Saturday, July 11, 2020

Invoking an object as a function in Kotlin JS

Some JavaScript libraries provide function objects with additional members. Expressing these as Kotlin objects in external class declarations is somewhat difficult. They can be given an operator fun invoke and called like a function using method call syntax, but the compiler will produce a call to an invoke method that doesn't exist. That could be re-@JsNamed to call and appear to work in some cases, but it's not really the right thing to do since call has the special behavior of setting this.

The expected approach seems to be to drop to weak typing by reinterpreting the object as a function. The class can be given an inline extension operator invoke along these lines:

inline operator fun Express.invoke(): ExpressApp {
    return this.unsafeCast<() -> ExpressApp>()()
}

Alternatively the receiver can be treated as the dynamic type:

inline operator fun Express.invoke(): ExpressApp {
    return this.asDynamic()() as ExpressApp
}

Wednesday, July 8, 2020

Watch out for returns inside inline functions

Blocks passed to Kotlin inline functions can return from the function calling the inline one - this is one of the advantages of inline functions. However, the inline function should be very careful that it's safe to return successfully (not just exceptionally) after calling a block passed to it. Today I was stumped for a bit on a database transaction wrapper function that mysteriously failed to issue the "commit" command after running the block. The block passed to it contained a plain return statement, which exits the entire enclosing function, when I meant to return a value from the block. The immediate fix was to change the return to return@theInlineFunction, but to avoid the issue in the future I adjusted the inline function to issue the commit in a "finally" block after checking that the "catch" block was not triggered by a crash in the block.

Monday, July 6, 2020

Running Kotlin Node JS projects outside Gradle

It's pretty easy to set up a Kotlin JS project targeting Node JS using the Kotlin JS Gradle plugin, but it's less easy to figure out how to actually run it on a server. The build/js folder contains the compiled JavaScript code, but accompanied by a ton of unnecessary stuff like copies of artifacts that are available on NPM. The compiled version of just the project under development is in a subdirectory of build/js/packages named for the project. Though that folder contains a package.json file that npm install can use, there is no clear way to start the app. For it to work with environments like Passenger, I amended the build process to write an app.js file there containing only:

require('./kotlin/the-project.js'); 

Then only the directory containing that new app.js has to be deployed.

Tuesday, June 30, 2020

Kotlin JS should usually catch Throwable

As I worked on starting a Node application in Kotlin JS, I found that one of my endpoints failed when tested by Invoke-WebRequest with an error about an incomplete response. I knew this indicated a crash in my endpoint handler, but it was not obvious how to get details on what went wrong. A try-catch block to handle Exceptions did not catch anything. Changing the catch block to handle all Throwables, however, caught the problem and was able to display it.

Saturday, June 27, 2020

No clear way to store resources in Kotlin JS projects

I'm working on a Node JS application written in Kotlin with the new Kotlin JS plugin. I needed to include some static files (web page templates) with the application, but it is not at all clear how I should connect them to the project. Gradle created a resources folder, but items in it didn't seem to be copied to anywhere in the build output. It looks like the old Kotlin2Js plugin worked with Webpack for deployment (?), but I see no such configuration or build step in my project. So I rigged up a post-compile step to just copy all the resources to the same folder as the compiled JavaScript files:
tasks.getByName("compileKotlinJs") {
    val resFolder = project.file("src/main/resources")
    inputs.dir(resFolder)
    doLast("copy resources") {
        resFolder.copyRecursively(project.file("build/js/packages/${project.name}/kotlin"), true)
    }
}

Monday, June 8, 2020

The kotlin.js plugin obsoletes kotlin2js

I tinkered with a new Kotlin for JavaScript project today and ran into some confusion. The documentation I found frequently mentioned features that didn't seem to be recognized by Gradle and third-party examples did a lot of things that I wouldn't have expected to be necessary. Older documentation mentioned applying a kotlin2js plugin, which apparently had a lot of features but is deprecated in favor of the new Kotlin JS plugin that is applied by default when creating a Kotlin/JS project in IntelliJ. Alternatively, it can be added as a plugin with kotlin("js")

Manual Node setup doesn't seem to be necessary. Dependencies from NPM can be added with implementation(npm(artifact, version)) in the standard dependencies block. I have not yet found a good way to package and deploy for NodeJS, though.