JS frontend

Eliminate dead code with Kotlin 1.1.4

Posted on by Gyula Voros

Context

Recently JetBrains released Kotlin 1.1.4 and the JavaScript compiler/tooling got some exciting new features. One of them is a new Gradle plugin called kotlin-dce-js (dce stands for dead code elimination). According to the documentation:

This tool allows to strip out unused properties, functions and classes from the generated JS. There are several ways you get unused declarations:

  • Functions can be inlined and never get called directly (which happens always except for few situations).
  • You are using a shared library which provides much more functions than you actually need. For example, standard library (kotlin.js) contains functions for manipulating lists, arrays, char sequences, adapters for DOM, etc, which together gives about 1.3 mb file. A simple "Hello, world" application only requires console routines, which is only few kilobytes for the entire file.

Not long ago, I gave a talk about Kotlin and how to use it for web development. For demo purposes, I've implemented an example full-stack TodoMVC application: https://github.com/gyulavoros/kotlin-todomvc. One of the first questions from the audience were: "What is the footprint of using Kotlin in the browser?", "Would you recommend to use Kotlin for real-world projects?" The answers back then were: "Quite heavy." and "Maybe?" After reading about the new code elimination tool I was curious about its performance, so I took it for a test drive.

If you are not familiar with kotlin-js, I recommend that you take a look at the following resources before you continue reading:

Setup

Integrating the DCE tool is super easy. You simply add a new plugin to the Gradle build script:

apply {
  plugin("kotlin2js")
  plugin("org.jetbrains.kotlin.frontend")
  plugin("kotlin-dce-js")
}

Unfortunately for now, the org.jetbrains.kotlin.frontend and kotlin-dce-js plugins don't play nice together, so I had to customize the webpack configuration. The issue is that by default, webpack will resolve kotlin and kotlinx-html-js dependencies from the node_modules folder, so the final bundle won't include the minified resources. I added a new dce.js config file to the webpack.config.d folder with the following content:

var path = require("path");
config.resolve.modules.unshift(path.resolve("./js/min"));

making sure that webpack will pick up files from the js/min folder first, where kotlin-dce-js is generating its output.

Results

The original version of the TodoMVC app weighted around 2 megabytes. After eliminating dead code and minifying the bundle the app now is 208 kilobytes.

steps size
unbundled frontend.js 36 KB
no DCE, no minifying 1932 KB
no DCE, minifying 907 KB
DCE, no minifying 430 KB
DCE, minifying 208 KB
DCE, minifying, gzip 47 KB

After gzip compression, the final size is 47 KB which is quite reasonable.

If you want to play with the DCE tool yourself, you can find a working example in my TodoMVC repo.

I'm happy to see how Kotlin is evolving to be a viable alternative for targeting JavaScript. I very much like what Scala.js became over the years, it would be nice to see a just as live ecosystem around Kotlin.js one day.