· 6 min read Posted by Gustavo Fão Valvassori

Measuring and analyzing the KotlinJS bundle size

Smaller JavaScript bundle size helps improve a website's loading speed and performance. In this article, we present two different ways of analyzing and measuring KotlinJS bundle size.
Sven Mieke - https://unsplash.com/pt-br/fotografias/lapis-marrom-sobre-papel-de-impressao-branco-fteR0e2BzKo?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash
Credit: Sven Mieke - https://unsplash.com/pt-br/fotografias/lapis-marrom-sobre-papel-de-impressao-branco-fteR0e2BzKo?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash

In the web development world, the application size is one of the key metrics for application performance. One of the most common ways to reduce it, is to compile all your project files into a single JS file (also known as a bundle). This technique will reduce requests to the server and the amount of transferred data.

Building your KotlinJS Application

Before reaching the measurement part, we need to have a minimal understanding of how a KotlinJS application is built. I won’t dive into it, but I will give you a quick overview.

First of all, KotlinJS does not run directly in the browser. It needs to be compiled (in this case, transpiled) into JavaScript. That’s what the Kotlin Gradle Plugin does. When you build a KotlinJS project, all your modules and dependencies will be “converted” into JS code. Those files are found in the build/js/packages/<module-name>/kotlin folder.

Now that we have a “JS equivalent project”, the next step is bundling all those JS files into one, and Webpack does this. Webpack is a modular static bundler for JavaScript. In addition to compiling all your code into a single file, you can extend it with plugins to perform other tasks, such as minification, tree shaking, and more.

This is a simplified explanation of the KotlinJS compilation. The complete version has more steps, like the generation of the Intermediate Representation, but this will not be relevant to this topic.

Webpack

As mentioned before, Webpack is a modular static bundler for KotlinJS. It is one of the most common bundlers used for web development. Because of its popularity, there is a vast diversity of plugins and extensions.

For most cases, the default configuration of KotlinJS will prepare Webpack to bundle your project. However, if you want, you can extend the base configuration.

Simple customizations can be made in the Gradle DSL using the webpackTask and commonWebpackConfig functions.

kotlin {
    js(IR) {
        browser {
            commonWebpackConfig {
                // Enabling webpack support for CSS/SCSS inside Gradle
                cssSupport { enabled.set(true) }
                scssSupport { enabled.set(true) }
            }
            webpackTask {
                // Renaming the final output file 
                mainOutputFileName = "my-output-file-name.js"

                // Changing development port
                devServer = KotlinWebpackConfig.DevServer(port = 8081)
            }
        }
    }
}

If you need to do something more complex, you must create a webpack.config.d directory with JavaScript configuration code. You should create this directory inside your module directory.

Here is an example configuring the UglifyJsPlugin.

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

config.optimization = config.optimization || {}
config.optimization.minimizer = config.optimization.minimizer || []
config.optimization.minimizer.push(new UglifyJsPlugin())
The KotlinJS already has a minification configuration; overriding it with Uglify may have negative impacts on your bundle size.

Measuring your bundle

Now that we have a basic overview of what it’s called and how to set it up, we can start with the measuring part. We can do it in two different ways.

  1. Analyze the Source map using SourceMapExplorer or Chrome LightHouse;
  2. Use the WebpackBundleAnalyzer;

Source map

The source map is a file that contains a mapping between the original source code and the generated code. The browser uses it to identify the place in the original source code that generated a specific line in the bundle.

This feature lets the browser show you the original code in the DevTools instead of the generated code. That’s why when you debug KotlinJS, you can still put breakpoints in the Kotlin classes. But there are other uses for it. You can also use it to inspect your bundle and see how much space each file takes.

As mentioned before, you can do that in two different ways. Let’s start with the SourceMapExplorer. First, you need to install it by following the official docs. After that, you can run the following command:

$ ./gradlew jsBrowserProductionWebpack # Build the KotlinJS application
$ source-map-explorer build/dist/js/productionExecutable/*.js* # Analyze the bundle

This will open a browser tab with the report result. It will look like this:

Another way of doing the same thing is by using Chrome LightHouse. It’s a tool that can help you analyze your application in many ways. You can use it to measure performance, accessibility, best practices, SEO, and more from your application.

To use it, you need to install it from the Chrome Web Store. After that, the option will be available on your Chrome DevTools.

After opening it, you can run a simple audit with only the Performance option enabled. It will generate a report similar to the one below. Lastly, when you click the “View TreeMap” button, you will have a report similar to the SourceMapExplorer.

Bundle Analyzer HTML Report

As mentioned before, Webpack is famous for its extensibility. Just like we previously made to integrate uglify, you can use other libraries that help you measure the output effortlessly. One of those plugins is the WebpackBundleAnalyzer.

With this plugin, you can generate a report of your bundle and see how much space each module weighs. To use it, you need to install it on your npm dev dependencies and configure the webpack to use it.

// file: /path/to/your/module/build.gradle.ks
kotlin {
    sourceSets {
        val jsMain by getting {
            dependencies {
                // Include WebpackBundleAnalyzer as dev dependency
                implementation(devNpm("webpack-bundle-analyzer", webpackVersion))
            }
        }
    }
}
// file: /path/to/your/module/webpack.config.d/bundleAnalyzer.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

config.plugins.push(
    new BundleAnalyzerPlugin({
        analyzerMode: 'static',
        openAnalyzer: false,
        generateStatsFile: true,
    }),
)

With the setup ready, you must re-build your application.

$ ./gradlew jsBrowserProductionWebpack
$ ls -la /path/to/your/module/build/dist/js/productionExecutable
.rw-r--r--@ 388k faogustavo staff compose-sweeper.js
.rw-r--r--@ 420k faogustavo staff compose-sweeper.js.map
.rw-r--r--@  365 faogustavo staff index.html
.rw-r--r--@ 276k faogustavo staff report.html
.rw-r--r--@ 1.1k faogustavo staff report.json
.rw-r--r--@  89k faogustavo staff stats.json

As you can see, it generates two different report formats:

  1. An HTML report;
  2. A JSON report;

The HTML can be opened in any browser. The result will be similar to the one below:

And the JSON file can be used by other tools, like the WebpackVisualizer.

Final Thoughts

In this article, we learned how to measure your KotlinJS application size and visualize the impact of libraries and classes.

Those two alternatives are the most commonly used by JS devs, but other tools can be helpful for your cases. If you are curious about this topic, we recommend checking other articles and tools that are more focused on Javascript, as most of those tools can be used for KotlinJS.