<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Touchlab</title>
    <description>The latest articles on Forem by Touchlab (@touchlab).</description>
    <link>https://forem.com/touchlab</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F1320%2F807eb679-1cc4-4ecc-b315-5d0a13093104.png</url>
      <title>Forem: Touchlab</title>
      <link>https://forem.com/touchlab</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/touchlab"/>
    <language>en</language>
    <item>
      <title>Kotlin 1.9.20: Streamlining Source Sets in Multiplatform Project</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Tue, 26 Mar 2024 13:57:17 +0000</pubDate>
      <link>https://forem.com/touchlab/kotlin-1920-streamlining-source-sets-in-multiplatform-project-27ak</link>
      <guid>https://forem.com/touchlab/kotlin-1920-streamlining-source-sets-in-multiplatform-project-27ak</guid>
      <description>&lt;p&gt;The release of Kotlin 1.9.20 marked a significant milestone for Kotlin Multiplatform enthusiasts, as this update moved Kotlin Multiplatform to Stable. Kotlin 1.9.20 introduces several notable &lt;a href="https://kotlinlang.org/docs/whatsnew1920.html"&gt;features and enhancements&lt;/a&gt;. Among these updates, the new source set hierarchy template by the Kotlin Gradle Plugin stands out to me for its ability to simplify configuration complexities. It was launched as experimental in Kotlin 1.8.20 and has been made default in Kotlin 1.9.20.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simplified iOS Target Configuration
&lt;/h2&gt;

&lt;p&gt;In the common Kotlin Multiplatform project set-up, you would have seen specific source set setup for two or three iOS targets like for X64, Arm64.&lt;/p&gt;

&lt;p&gt;Instead of the common and confusing 'ios()' target, one must always declare specific targets like 'iosArm64()' as required. Once one of the iOS targets is declared, the default template would automatically create &lt;code&gt;iosMain&lt;/code&gt; source set. So no more &lt;code&gt;val iosMain by creating&lt;/code&gt; boilerplate required.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt; Before 1.9.20 &lt;/td&gt; &lt;td&gt; After 1.9.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;

&lt;pre&gt;
kotlin {
    ios()
    iosSimulatorArm64()

    sourceSets {
        val commonMain by getting

        val iosMain by creating {
            dependsOn(commonMain)
        }

        val iosX64Main by getting {
            dependsOn(iosMain)
        }

        val iosArm64Main by getting {
            dependsOn(iosMain)
        }

        val iosSimulatorArm64Main by getting {
            dependsOn(iosMain)
        }
    }
}

&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;

&lt;pre&gt;
kotlin {
    iosX64()
    iosArm64()
    iosSimulatorArm64()

    // The iosMain source set is now created automatically
    // You can directly use the reference now
    iosMain.dependencies {
        implementation("...")
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;If you've an old KMP project and still have reference of &lt;code&gt;darwinMain&lt;/code&gt;, you can simply rename it to &lt;code&gt;appleMain&lt;/code&gt; now as that encapsulates all other apple targets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://kotlinlang.org/docs/whatsnew1920.html#see-the-full-hierarchy-template"&gt;Checkout&lt;/a&gt; the full hierarchy template!&lt;/p&gt;

&lt;h2&gt;
  
  
  Streamlined Custom Source Sets
&lt;/h2&gt;

&lt;p&gt;Managing custom source sets in Kotlin Multiplatform projects is now more straightforward with Kotlin 1.9.20. The update simplifies the process of setting up dependencies between source sets, reducing the need for extensive boilerplate code and enhancing overall readability.&lt;/p&gt;

&lt;p&gt;For example, let's assume that you already have &lt;code&gt;kotlin/JS&lt;/code&gt; support with &lt;code&gt;jsMain/jsTest&lt;/code&gt; source sets. Now, you want to add &lt;code&gt;kotlinWasm&lt;/code&gt; support. Since &lt;code&gt;wasmJs&lt;/code&gt; and &lt;code&gt;kotlinJs&lt;/code&gt; can share a common source, you want to introduce a new &lt;code&gt;jsAndWasmJsMain&lt;/code&gt; parent source set for common code sharing between them. Instead of using &lt;code&gt;by creating&lt;/code&gt;, you can declare new custom source set inside &lt;code&gt;applyDefaultHierarchyTemplate {}&lt;/code&gt;.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt; Before 1.9.20 &lt;/td&gt; &lt;td&gt; After 1.9.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    js()
    wasmJs()

    sourceSets {
        val commonMain by getting
        val commonTest by getting

        val jsAndWasmJsMain by creating {
            dependsOn(commonMain)
            getByName("jsMain").dependsOn(this)
            getByName("wasmMain").dependsOn(this)
        }

        val jsAndWasmJsTest by creating {
            dependsOn(commonTest)
            getByName("jsTest").dependsOn(this)
            getByName("wasmTest").dependsOn(this)
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    js()
    wasmJs()

    // This is an experimental API, so opt-in is required
    @OptIn(ExperimentalKotlinGradlePluginApi::class)
    applyDefaultHierarchyTemplate {
        // create a new group that
        // depends on `common`
        common {
            // Define group name without
            // `Main` as suffix
            group("jsAndWasmJs") {
                // Provide which targets would
                // be part of this group
                withJs()
                withWasm()
            }
        }
    }

    // Now you will already have `jsAndWasmJsMain`
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Manually apply the template
&lt;/h3&gt;

&lt;p&gt;Note that if you have explict &lt;code&gt;by creating&lt;/code&gt; usage for custom source set then defauly template hierarchy would not apply automatically and you would see warning about the same.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;w: The Default Kotlin Hierarchy Template was not applied to 'project ':XXX'':
Explicit .dependsOn() edges were configured for the following source sets:
[XXX]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to get the default hierachy, you would have to call &lt;code&gt;applyDefaultHierarchyTemplate()&lt;/code&gt; manually once you declare all the targets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Also, checkout Opting Out of Default Templates&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Enhanced Code Completion Support
&lt;/h2&gt;

&lt;p&gt;The updated source set hierarchy template enhances code completion support in the IDE. Developers can now utilize predefined source sets directly, eliminating the need for repetitive declarations and enhancing overall development efficiency.&lt;/p&gt;

&lt;p&gt;So even in simple cases, you can still clean up your source set declarations, and make them more readable.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt; Default before 1.9.20 &lt;/td&gt; &lt;td&gt; With 1.9.20 &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    // ...
    sourceSets {
        val commonMain by getting {
            dependencies {
                // ...
            }
        }
        val androidMain by getting {
            dependencies {
                // ...
            }
        }
        val iosMain by creating {
            dependencies {
                // ...
            }
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    // ...
    sourceSets {
        commonMain.dependencies {
            // ...
        }
        androidMain.dependencies {
            // ..
        }
        iosMain.dependencies {
            // ...
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Android instrumented test changes
&lt;/h2&gt;

&lt;p&gt;With introduction of the new Android source set layout (now default starting Kotlin 1.9.0), the &lt;code&gt;androidInstrumentedTest&lt;/code&gt; source set doesn't automatically depend on &lt;code&gt;commonTest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to have that dependency set-up, with 1.9.0, you would need to explicitly set the &lt;code&gt;dependsOn&lt;/code&gt; relationship between them, and with 1.9.20, you now just need to set the correct &lt;code&gt;sourceSetTree&lt;/code&gt; property inside android target.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tr&gt;
&lt;td&gt; With 1.9.0 &lt;/td&gt; &lt;td&gt; With 1.9.20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    // ...
    sourceSets {
        val commonTest by getting
        val androidInstrumentedTest by getting {
            dependsOn(commonTest)
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;pre&gt;
kotlin {
    androidTarget {
        // This is an experimental API, so opt-in is required
        @OptIn(ExperimentalKotlinGradlePluginApi::class)
        instrumentedTestVariant {
            // This makes instrumented tests depend on commonTest source
            sourceSetTree.set(KotlinSourceSetTree.test)
        }
    }
}
&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Opting Out of Default Templates
&lt;/h2&gt;

&lt;p&gt;For projects with existing complex source set hierarchies, Kotlin 1.9.20 offers the flexibility to opt-out of the default template. By setting &lt;code&gt;kotlin.mpp.applyDefaultHierarchyTemplate=false&lt;/code&gt; in the &lt;code&gt;gradle.properties&lt;/code&gt;, developers can retain their current configurations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;As you transition to Kotlin 1.9.20, consider how these improvements can optimize your Gradle configurations and enhance your multiplatform development workflow.&lt;/p&gt;

&lt;p&gt;We recently updated most of our OSS projects to use Kotlin 1.9.22, leveraging the benefits of these enhancements. We hope you find the transition as beneficial as we have.&lt;/p&gt;




&lt;p&gt;Share your experiences and questions with us on #touchlab-tools channel on Kotlin Slack. Also, you can reach out to me at &lt;a class="mentioned-user" href="https://dev.to/shaktiman_droid"&gt;@shaktiman_droid&lt;/a&gt; on Twitter(X) or LinkedIn. Happy coding!&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>gradle</category>
      <category>kmp</category>
    </item>
    <item>
      <title>Amper: a new way to configure Gradle projects?</title>
      <dc:creator>Gustavo Fão Valvassori</dc:creator>
      <pubDate>Fri, 08 Dec 2023 12:05:34 +0000</pubDate>
      <link>https://forem.com/touchlab/amper-a-new-way-to-configure-gradle-projects-3abf</link>
      <guid>https://forem.com/touchlab/amper-a-new-way-to-configure-gradle-projects-3abf</guid>
      <description>&lt;p&gt;Earlier this month, Kotlin Multiplatform went stable. And just a couple of weeks later, they announced a new tool to help with one of the biggest issues we have, configuration. Currently, KMP projects use Gradle as a Build System, and we must agree that it's a great tool. But the complexity around it for new users is a big issue.&lt;/p&gt;

&lt;p&gt;Amper is a tool to help you configure your projects using a markup language. The main goal is to replace the Groovy/Kotlin programming language with something that can enforce a declarative approach. With a declarative paradigm,  you can only declare what needs to be done without implementing it. If you already have experience with Maven, it may be familiar to you.&lt;/p&gt;

&lt;p&gt;Please note that the tool is in the early stages of development, and its goal is to validate the idea before putting more effort into it. With that in mind, be aware that syntax, language, and other things may change in the future, and it’s a very experimental tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it work?
&lt;/h2&gt;

&lt;p&gt;According to the docs, &lt;code&gt;Amper is implemented as a Gradle plugin and uses YAML for its project configuration format&lt;/code&gt;. In other words, it's still a Gradle environment, but it will use an additional YAML file to configure the project. To be able to use it, you need one of the following environments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use one of the following IDEs:

&lt;ol&gt;
&lt;li&gt;IntelliJ IDEA 2023.3 or newer and the Amper Plugin; or&lt;/li&gt;
&lt;li&gt;Fleet 1.26 or newer;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Use the Amper build plugin to enable it:

&lt;ol&gt;
&lt;li&gt;In your &lt;code&gt;settings.gradle.kts&lt;/code&gt;, add this plugin: &lt;code&gt;id("org.jetbrains.amper.settings.plugin").version("0.1.1")&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When you open a project with the Amper Plugin in the IDE, it will look for the &lt;code&gt;module.yaml&lt;/code&gt; file. This file will contain the configuration for the module (library or application), dependencies, and other project configurations (like the Java version).&lt;/p&gt;

&lt;p&gt;Also worth noting that it also changes the project architecture. Instead of having a directory for your source set artifacts, you will have multiple &lt;code&gt;src&lt;/code&gt; directories. In other words, your &lt;code&gt;commonMain/src/kotlin&lt;/code&gt; will be only &lt;code&gt;src&lt;/code&gt; now, and your &lt;code&gt;iosMain/src/kotlin&lt;/code&gt; will be only &lt;code&gt;src@ios&lt;/code&gt;. This is a bit confusing at first, but it helps flatten the project structure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sUhLP2iw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./img.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sUhLP2iw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/v1/./img.png" alt="Amper Project Example" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Thoughts
&lt;/h2&gt;

&lt;p&gt;Amper comes to fix a huge problem for all KMP developers. We at Touchlab look forward to anything that will reduce the configuration complexity in KMP, and Amper is hopefully a step in the right direction. The Gradle team &lt;a href="https://blog.gradle.org/declarative-gradle"&gt;seems to be on board&lt;/a&gt;, at least with the concept. Hopefully the combined efforts will result in something that is truly easier to use and more maintainable.&lt;/p&gt;

&lt;p&gt;The integration with the IDEs works fine for configuration. It knows the configuration schema and gives you valid suggestions for properties. Unfortunately, the configuration of the third-party plugins is not currently supported, but it's on their roadmap.&lt;/p&gt;

&lt;p&gt;The project APIs are small and only supports a short range of configurations. For basic contexts it works like a charm, but when you need to do something more complex, you may need to work with Gradle again.&lt;/p&gt;

&lt;p&gt;The Gradle interop is great. You can still have a &lt;code&gt;build.gradle.kts&lt;/code&gt; file to make custom configurations that are not available yet in the YAML file. One does not replace the other, but complement instead. This will be useful if you need to create intermediate source-sets, configure plugins or even import libraries that have a different configuration.&lt;/p&gt;

&lt;p&gt;For now, we recommend testing it it out on smaller projects that may not have a big impact with future changes, as it's still experimental. But we are excited to see how it will evolve in the future. If you are using it, don't forget to share your opinions with the Jetbrains team on their &lt;a href="https://surveys.jetbrains.com/s3/Amper-feedback-form"&gt;Feedback Form&lt;/a&gt; and their &lt;a href="https://kotlinlang.slack.com/archives/C062WG3A7T8"&gt;Slack Channel&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.jetbrains.com/blog/2023/11/09/amper-improving-the-build-tooling-user-experience/"&gt;Official Announcement&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.jetbrains.com/kotlin/2023/11/kotlin-multiplatform-tooling-in-fleet/"&gt;Welcome Fleet with Kotlin Multiplatform Tooling&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/JetBrains/amper/"&gt;Github Project&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://surveys.jetbrains.com/s3/Amper-feedback-form"&gt;Feedback Form&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Getting Started with Compose for Web</title>
      <dc:creator>Gustavo Fão Valvassori</dc:creator>
      <pubDate>Fri, 01 Dec 2023 21:34:32 +0000</pubDate>
      <link>https://forem.com/touchlab/getting-started-with-compose-for-web-455n</link>
      <guid>https://forem.com/touchlab/getting-started-with-compose-for-web-455n</guid>
      <description>&lt;p&gt;If you are a Kotlin developer like me, you are probably very excited about Jetpack Compose. It’s a modern UI toolkit for developing apps, and with the great work from JetBrains, it’s becoming a really interesting solution.&lt;/p&gt;

&lt;p&gt;As a mobile developer, I’ve never gone in the weeds on how to properly develop sites with HTML, CSS, and JS. My closest experience was with React Native back in 2018. But now, with Compose, using a Kotlin DSL, I feel comfortable on doing this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compose Runtime and Component Library
&lt;/h2&gt;

&lt;p&gt;Before creating a project and start coding, it's important to have a small introduction to Compose runtimes. As of now, Compose has two different runtimes on the web:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;JS + HTML&lt;/li&gt;
&lt;li&gt;Wasm + Canvas&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;They both use the Compose Runtime underneath, but they use different components. Long story short: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The HTML version will have HTML composable components (like H1, P, Span, Input, Div, etc.) &lt;/li&gt;
&lt;li&gt;The Canvas version will have similar components as the Android version as it uses SKIA to draw on the Canvas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both of them are experimental. Note that choosing how you want to build your application will impact on possible code-sharing with native if this is what you want.&lt;/p&gt;

&lt;p&gt;For this series of posts, I'll use the HTML version and I will be able to explore more the web components.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating the project
&lt;/h2&gt;

&lt;p&gt;Now that we know what runtime/components we want to use, we need to create a project. My first idea was to use the &lt;a href="https://kmp.jetbrains.com" rel="noopener noreferrer"&gt;KMP project wizard&lt;/a&gt;, but unfortunately, the Web target is not available as an option for now. As a workaround, I had to create a new clean project using IntelliJ IDEA and add the dependencies manually. &lt;/p&gt;

&lt;p&gt;Using a clean template you will reduce the amount of code that needs to be removed/updated to make the project work. But if you prefer to use any other IDE/Template, feel free to do so and share your experience with us later :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feya3ykaxbvtitksa51ff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feya3ykaxbvtitksa51ff.png" alt="IntelliJ IDEA Project Wizard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With that, the configuration is completed with a few extra lines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change the Kotlin plugin from JVM to MULTIPLATFORM&lt;/li&gt;
&lt;li&gt;Add the Compose plugin&lt;/li&gt;
&lt;li&gt;Declare JS source-sets&lt;/li&gt;
&lt;li&gt;Import the dependencies&lt;/li&gt;
&lt;li&gt;Create an HTML file&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;plugins&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"multiplatform"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.9.20"&lt;/span&gt; &lt;span class="c1"&gt;// Make this multiplatform&lt;/span&gt;
    &lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"org.jetbrains.compose"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s"&gt;"1.5.10"&lt;/span&gt; &lt;span class="c1"&gt;// Add compose plugin&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// Declare JS source-sets&lt;/span&gt;
        &lt;span class="nf"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;binaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;jsMain&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;getting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                                &lt;span class="c1"&gt;// Import libraries&lt;/span&gt;
                &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;jsTest&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;getting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependencies&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;implementation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test-js"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you have a trained eye for Gradle configuration, you probably already noticed that we are importing the Compose HTML library. And that's why we need to create an HTML page that will load and be filled by our Composable code. This file should be located at &lt;code&gt;jsMain/resources/index.html&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Compose Web&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"compose-sweeper.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This can be very simple, just load the JS built from your Kotlin code and create a DOM element that will be you compose root.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;p&gt;As with any other project using Gradle as the build system, you will run most of your changes with the &lt;code&gt;gradlew&lt;/code&gt; binary (or the &lt;code&gt;gradlew.bat&lt;/code&gt; if you are running on Windows). Even though there are multiple commands listed when you call &lt;code&gt;gradlew tasks&lt;/code&gt;, the important ones are three:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;./gradlew jsBrowserDevelopmentRun&lt;/code&gt; - Start development server;

&lt;ol&gt;
&lt;li&gt;This call supports the &lt;code&gt;--continuous&lt;/code&gt; build flag that can be used for reloading the app when the code changes;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;./gradlew jsBrowserProductionWebpack&lt;/code&gt; - Generate the bundle version of your project. 

&lt;ol&gt;
&lt;li&gt;It will spit out a static site at the &lt;code&gt;build/dist/js/productionExecutable&lt;/code&gt; dir;&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;./gradlew allTests&lt;/code&gt; - Run all unit tests you have implemented for your project;&lt;/li&gt;

&lt;/ol&gt;

&lt;h2&gt;
  
  
  How does this work?
&lt;/h2&gt;

&lt;p&gt;When you start the development server, it will compile your Kotlin code and run the &lt;code&gt;main()&lt;/code&gt; function. On this function, you can call the &lt;code&gt;renderComposable&lt;/code&gt; method to start a composable block inside a window element.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;renderComposable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rootElementId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As you can see, it will render all the content inside one root element we've defined on previous sections.&lt;/p&gt;

&lt;p&gt;Lastly, as you can see at the end of the body block, we are importing the JS file created while building our application. The default name is just the project name with a &lt;code&gt;.js&lt;/code&gt; extension.&lt;/p&gt;

&lt;p&gt;Now that we have everything in place, we can finally run our server and have the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev7qpzkze4g7w0yr7vn6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev7qpzkze4g7w0yr7vn6.png" alt="Compose Hello Wold"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In this first article, we are just exploring how to create and set up your project. But we can already say that Compose Web is a promising alternative for Kotlin developers who don’t want to learn HTML/CSS/JS (even though you will need it). &lt;/p&gt;

&lt;p&gt;In future posts, we will dig into more topics, like how to use HTML Components, Styling with CSS, Handling, and Listening to DOM events. After all the articles, you will be able to fully understand how I’ve built &lt;a href="https://faogustavo.github.io/compose-sweeper/" rel="noopener noreferrer"&gt;this Minesweeper game&lt;/a&gt; only using Compose.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>compose</category>
      <category>multiplatform</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Kermit Now Supports WASM</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 30 Oct 2023 19:09:32 +0000</pubDate>
      <link>https://forem.com/touchlab/kermit-now-supports-wasm-356p</link>
      <guid>https://forem.com/touchlab/kermit-now-supports-wasm-356p</guid>
      <description>&lt;h2&gt;
  
  
  What is Kotlin/Wasm?
&lt;/h2&gt;

&lt;p&gt;For Kotlin Multiplatform developers, the conversation has shifted to WebAssembly — a notable addition to the Kotlin Multiplatform (KMP) ecosystem. &lt;a href="(https://en.wikipedia.org/wiki/WebAssembly)"&gt;WebAssembly&lt;/a&gt;, often abbreviated as WASM, is a binary instruction format tailored for web browsers. Its main goal is to execute high-performance code at speeds close to native applications. WebAssembly enjoys broad support across modern browsers, boasting approximately 96% coverage according to &lt;a href="https://caniuse.com/wasm"&gt;caniuse&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While it's not meant to be directly written, there's a fascinating aspect called &lt;code&gt;WebAssembly Text Format (.wat)&lt;/code&gt;. This format allows developers to represent code in a readable text format. For those curious minds, delve deeper into this format by reading &lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly/Understanding_the_text_format"&gt;Mozilla's guide&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While WebAssembly isn't a newcomer, ongoing developments, such as the anticipated &lt;a href="https://github.com/WebAssembly/gc"&gt;WebAssembly Garbage Collection (WASM GC)&lt;/a&gt;, make it an evolving technology. Kotlin, recognizing the potential of WebAssembly, has embraced it with the Kotlin/WASM compiler. The Kotlin team is actively ensuring they stay ahead of the curve with the Kotlin/WASM compiler, already incorporating support for features like WASM GC. What makes Kotlin/WASM noteworthy is its ability to allow developers to write code in their preferred language and seamlessly compile it into a WebAssembly binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kermit Steps into the Wasm Arena
&lt;/h2&gt;

&lt;p&gt;Given Kermit's popularity in the Kotlin Multiplatform (KMP) realm, the community asked for Wasm support. It was exciting to gain firsthand experience with WASM for integration into Kermit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #1 - Adding the Wasm Target
&lt;/h3&gt;

&lt;p&gt;The initial step seemed straightforward: add the &lt;code&gt;wasm&lt;/code&gt; target in our build scripts. However, reality hit when we discovered that some of Kermit's dependencies lacked support for Wasm. This underscored a critical lesson for library developers: &lt;strong&gt;ensure upstream libraries are compatible with all KMP targets your project aims to include&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl&lt;/span&gt;

&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
    &lt;span class="nd"&gt;@OptIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ExperimentalWasmDsl&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;wasm&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;binaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;You can also add &lt;code&gt;nodejs&lt;/code&gt; and &lt;code&gt;d8&lt;/code&gt; environment support inside the &lt;code&gt;wasm&lt;/code&gt; target, but exploration around that is out of scope for this post.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step #2 - Common Source Set
&lt;/h3&gt;

&lt;p&gt;Understanding the possibility for &lt;a href="(https://kotlinlang.org/docs/wasm-js-interop.html)"&gt;interoperability&lt;/a&gt; between Kotlin/JS and Kotlin/Wasm, we defined a common source set shared between &lt;code&gt;js&lt;/code&gt; and &lt;code&gt;wasm&lt;/code&gt;. This approach ensures code reusability between the two targets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;jsAndWasmMain&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;creating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commonMain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;jsMain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;wasmMain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;jsAndWasmTest&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;creating&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;commonTest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;jsTest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;wasmTest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dependsOn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step #3 - Code Migration
&lt;/h3&gt;

&lt;p&gt;Migrating code from &lt;code&gt;jsMain&lt;/code&gt; to &lt;code&gt;jsAndWasmMain&lt;/code&gt; wasn't a simple copy-paste endeavor. Here, we encountered two challenges:&lt;/p&gt;

&lt;h4&gt;
  
  
  Problem #1: Console API Unavailability in Wasm
&lt;/h4&gt;

&lt;p&gt;The first hurdle we encountered was the absence of the &lt;a href="https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.js/-console/"&gt;console API&lt;/a&gt; in Wasm. In Kermit, we had the &lt;a href="https://github.com/touchlab/Kermit/blob/1fca73033063b3a52faa14b886d9e5422d2fca49/kermit-core/src/jsMain/kotlin/co/touchlab/kermit/ConsoleWriter.kt#L52"&gt;ConsoleActual&lt;/a&gt; object in JS, utilizing the console API to log data to the browser's console. To address this, we took the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Converted the ConsoleActual object to an expect object, establishing a mandatory object for JS and Wasm:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ConsoleActual&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ConsoleIntf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Moved the existing object with console calls to &lt;code&gt;jsMain&lt;/code&gt; and created a new one for &lt;code&gt;wasmMain&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Problem #2: Wasm-JS Interop Limitations
&lt;/h4&gt;

&lt;p&gt;To call console from Wasm, we needed to invoke JavaScript from Wasm. While the usual &lt;code&gt;js()&lt;/code&gt; for inline JavaScript works for JS, Wasm required a different approach. The &lt;a href="https://kotlinlang.org/docs/wasm-js-interop.html#inline-javascript"&gt;@JSFun&lt;/a&gt; annotation proved useful, allowing us to execute JavaScript functions from Wasm. However, we encountered a problem with use of &lt;code&gt;Any?&lt;/code&gt; in the interface methods:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wasm.ConsoleActual.kt&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@JsFun&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"(output) =&amp;gt; console.error(output)"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;consoleError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;vararg&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt;

&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;ConsoleActual&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ConsoleIntf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;vararg&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;consoleError&lt;/span&gt;&lt;span class="p"&gt;(*&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, an inline error surfaced:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Type Any? cannot be used in an external function parameter. Only external, primitive, string, and function types are supported in Kotlin/Wasm JS interop.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To circumvent this limitation, we opted for a design change, using &lt;code&gt;String&lt;/code&gt; instead of &lt;code&gt;Any?&lt;/code&gt; for both JS and Wasm, as they share the same interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ConsoleIntf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;// other methods...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adjustment allowed smooth interaction between Wasm and JS, ensuring compatibility with the restricted set of supported APIs in Kotlin/Wasm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step #4 - Integration
&lt;/h3&gt;

&lt;p&gt;Drawing inspiration from Kotlin's &lt;a href="https://github.com/Kotlin/kotlin-wasm-examples/tree/main/browser-example"&gt;wasm-browser-sample&lt;/a&gt;, we created the &lt;a href="https://github.com/touchlab/Kermit/tree/main/samples/sample/wasm-browser"&gt;wasm-browser&lt;/a&gt; sample app. It mirrors the module structure of the app-browser app in our Kotlin/JS sample.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;p&gt;Our foray into Kotlin/Wasm integration was not without challenges. Key takeaways include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interoperability with JS is a work in progress, requiring careful consideration when sharing code between the two.&lt;/li&gt;
&lt;li&gt;Loading generated &lt;code&gt;.wasm&lt;/code&gt; files directly in web apps may pose challenges, especially around types. We couldn't get this to work in the short time we had.&lt;/li&gt;
&lt;li&gt;Debugging Wasm-related issues can be tricky; Our tests failure output wasn't easy to understand. Kotlin Slack proved to be an invaluable resource for troubleshooting. We learned that output with &lt;code&gt;--info&lt;/code&gt; flag shows the actual node command that's being executed. Calling that command directly showed better errors and we could fix the code then.&lt;/li&gt;
&lt;li&gt;Compatibility concerns arise regarding the version of &lt;code&gt;Node.js&lt;/code&gt;; Note that versions 1.9.20 onwards would require Node version and Browsers that support Wasm GC.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Feel free to explore the latest version of Kermit and dive into the exciting world of Kotlin/Wasm. Stay tuned for future updates and enhancements! Share your experiences and questions with us on &lt;a href="https://kotlinlang.slack.com/archives/CTJB58X7X"&gt;#touchlab-tools&lt;/a&gt; channel on Kotlin Slack. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid"&gt;@shaktiman_droid&lt;/a&gt; on Twitter(X) or &lt;a href="https://www.linkedin.com/in/shaktiman-droid/"&gt;LinkedIn&lt;/a&gt;. Happy coding!&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>kotlin</category>
      <category>webassembly</category>
      <category>logging</category>
    </item>
    <item>
      <title>Logger.i() Not Your Style? Customize Kermit Logger!</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Tue, 24 Oct 2023 02:19:28 +0000</pubDate>
      <link>https://forem.com/touchlab/loggeri-not-your-style-customize-kermit-logger-4fik</link>
      <guid>https://forem.com/touchlab/loggeri-not-your-style-customize-kermit-logger-4fik</guid>
      <description>&lt;p&gt;In the realm of Kotlin Multiplatform logging, the Kermit library stands as a trusted companion for developers. However, some find its conventional &lt;code&gt;logger.i&lt;/code&gt; syntax less appealing. What if you could improve your logging experience with a touch of personalization? Enter the world of custom logger, where &lt;code&gt;logger.info&lt;/code&gt; becomes a reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diving into Custom Logging
&lt;/h2&gt;

&lt;p&gt;The journey begins with a glance at a custom code snippet that transforms the Kermit logging experience. This code introduces a custom &lt;code&gt;Logger&lt;/code&gt; class adorned with methods like &lt;code&gt;info&lt;/code&gt;, and &lt;code&gt;error&lt;/code&gt;—a testament to the flexibility &lt;code&gt;Kermit&lt;/code&gt; provides for tailoring logging to your liking.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that example code below is a very toned down version of full Logger API. It helps with keeping the code minimal while still delivering the idea behind it.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;co.touchlab.kermit.BaseLogger&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;co.touchlab.kermit.LoggerConfig&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;co.touchlab.kermit.Severity&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;co.touchlab.kermit.mutableLoggerConfigInit&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;co.touchlab.kermit.platformLogWriter&lt;/span&gt;

&lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LoggerConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;open&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"MyDefaultTag"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;BaseLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;logBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;logBlock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messageString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;inline&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messageString&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;throwable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;messageString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;companion&lt;/span&gt; &lt;span class="k"&gt;object&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;mutableLoggerConfigInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;platformLogWriter&lt;/span&gt;&lt;span class="p"&gt;())))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now instead of calling Kermit's API, you can call your own methods.&lt;/p&gt;

&lt;p&gt;Call&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rather than&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;i&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Kermit-core
&lt;/h3&gt;

&lt;p&gt;This flexiblity comes from the modularized kermit components. If you prefer to have &lt;code&gt;custom&lt;/code&gt; logger then you need to only depends on &lt;code&gt;kermit-core&lt;/code&gt; instead of &lt;code&gt;kermit&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s"&gt;"co.touchlab:kermit-core:{{KERMIT_VERSION}}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Beyond syntax preferences, custom logger methods may include more flexibility matching your application's unique needs.&lt;/p&gt;

&lt;p&gt;Embrace the power of custom logging with &lt;code&gt;Kermit&lt;/code&gt;, and let your logs echo your coding identity. Happy logging!&lt;/p&gt;




&lt;p&gt;Let me know in the comments if you have questions. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid"&gt;@shaktiman_droid&lt;/a&gt; on Twitter(X), &lt;a href="https://www.linkedin.com/in/shaktiman-droid/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://kotlinlang.slack.com/archives/CTJB58X7X"&gt;#touchlab-tools&lt;/a&gt; channel on Kotlin Slack. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>kotlinmultiplatform</category>
      <category>kotlin</category>
      <category>logging</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Optimizing Gradle Builds in Multi-module Projects</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 16 Oct 2023 20:31:31 +0000</pubDate>
      <link>https://forem.com/touchlab/optimizing-gradle-builds-in-multi-module-projects-3ijp</link>
      <guid>https://forem.com/touchlab/optimizing-gradle-builds-in-multi-module-projects-3ijp</guid>
      <description>&lt;p&gt;You're not alone if you've also struggled with sluggish Gradle builds in a multi-module project. Recently, we undertook the challenge of significantly reducing build times for a client with over 100 Kotlin Multiplatform modules, and achieved a more than 50% boost in speed across platforms. In this post, we'll walk you through the steps we took. We hope it proves valuable to fellow developers facing similar challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benchmark Your Builds
&lt;/h2&gt;

&lt;p&gt;Before diving into optimizations, it's crucial to understand the baseline.  Gather build times from all team members, ensuring the Gradle build cache is disabled. Use handy &lt;code&gt;--no-build-cache&lt;/code&gt; option to any Gradle task command to run without build cache. Unsurprisingly, in our case, the Intel-based mac machines were really slow compared to Apple chip ones and we didn't have anyone with a Windows machine. This information is key for later comparison and improvement assessment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: One thing we realized that, some optimizations below might be more applicable to legacy or tech-debt-laden projects.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Tools for Insight
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gradle Build Scan
&lt;/h3&gt;

&lt;p&gt;Utilize the power of Gradle &lt;a href="(https://docs.gradle.org/current/userguide/inspect.html#what_is_a_build_scan)"&gt;Build Scan&lt;/a&gt; to delve into the details of your builds. In my opinion, it's not just a diagnostic tool; it's a learning tool.&lt;/p&gt;

&lt;p&gt;In our case, we uncovered insights into the sluggishness of &lt;code&gt;ios link&lt;/code&gt; tasks in the Kotlin Multiplatform setup. Comparing build scans on different CI machines helped identify the fastest configuration for a machine to use on our CI. Enabling parallel builds and analyzing the results through build scan reports further validated our improvements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android Studio Build Analyser
&lt;/h3&gt;

&lt;p&gt;Android Studio provides a &lt;a href="https://developer.android.com/build/build-analyzer"&gt;built-in analyser tool&lt;/a&gt;. It inspects build performance and provides warning around potential issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disable Jetifier&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Using this, we noticed the lingering &lt;code&gt;android.enableJetifier=true&lt;/code&gt; usage due to outdated &lt;code&gt;Picasso&lt;/code&gt; library that didn't use &lt;code&gt;AndroidX&lt;/code&gt; libraries. That might have hindered build speed too. Addressing this involved updating &lt;code&gt;Picasso&lt;/code&gt; and removing the &lt;code&gt;jetifier&lt;/code&gt; flag from &lt;code&gt;gradle.properties&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MultiDex&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Through the Build Analyser, we also found unnecessary use of &lt;code&gt;multiDexEnabled&lt;/code&gt; in few modules along with some old Gradle configurations. &lt;code&gt;MultiDex&lt;/code&gt; was unnecessary with &lt;code&gt;minSdkVersion&lt;/code&gt; as 21.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Visibility
&lt;/h2&gt;

&lt;p&gt;We observed a significant number of modules relying on other modules via &lt;code&gt;api&lt;/code&gt; dependency. The problem with having &lt;code&gt;api&lt;/code&gt; dependencies is that Gradle would &lt;code&gt;recompile&lt;/code&gt; them when implementation details change. It's because they appear on &lt;code&gt;compile&lt;/code&gt; classpaths. This can have significant &lt;code&gt;ripple&lt;/code&gt; of recompilations in a multi-module setup and affect the build times.&lt;/p&gt;

&lt;p&gt;To mitigate this, we shifted to using &lt;code&gt;implementation&lt;/code&gt; for most dependencies, reserving &lt;code&gt;api&lt;/code&gt; only for those exported as part of &lt;code&gt;XCFramework&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enable Gradle Parallel Execution
&lt;/h2&gt;

&lt;p&gt;In a multi-subproject setup, Gradle may benefit greatly from parallel execution. With the shift from &lt;code&gt;api&lt;/code&gt; to &lt;code&gt;implementation&lt;/code&gt;, &lt;a href="https://docs.gradle.org/current/userguide/performance.html#parallel_execution"&gt;enabling parallel execution&lt;/a&gt; further slashed build times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mindful Use of External Gradle Plugins
&lt;/h2&gt;

&lt;p&gt;Some Gradle plugins can be the culprits behind slower builds. Our project had a couple of Gradle plugins like that. They used to execute on every sync, every task and run through all the modules in the project.&lt;/p&gt;

&lt;p&gt;Scrutinize third-party plugins before integration, especially in a multi-module setup. Avoid unnecessary global application using &lt;code&gt;subproject&lt;/code&gt; or &lt;code&gt;allprojects&lt;/code&gt; blocks; apply plugins only where needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unnecessary KMP targets
&lt;/h2&gt;

&lt;p&gt;When managing Kotlin Multiplatform (KMP) projects, it's crucial to evaluate the necessity of added KMP targets. In our experience, we found that inadvertently adding targets that aren't required for the project can introduce inefficiencies.&lt;/p&gt;

&lt;p&gt;For instance, we had inherited some modules with added &lt;code&gt;JVM&lt;/code&gt; targets for certain KMP modules from older test modules. Over time, more modules were introduced, and the JVM target persisted without any actual use. This led to unnecessary JVM-related build and test tasks executing during the build phase.&lt;/p&gt;

&lt;p&gt;To address this, we recommend reviewing your KMP setup and removing any targets that don't contribute to the project's functionality. This not only streamlines the build process but also reduces unnecessary overhead, especially in a large multi-module project like ours.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build only required XCFramework
&lt;/h2&gt;

&lt;p&gt;In Kotlin Multiplatform (KMP) projects with iOS components, the iOS build task can be a significant contributor to extended build times. Often, KMP project script files include configurations for multiple iOS architectures using &lt;code&gt;iOSX64()&lt;/code&gt;, &lt;code&gt;iosArm64()&lt;/code&gt;, and &lt;code&gt;iosSimulatorArm64()&lt;/code&gt; targets, or the shorthand &lt;code&gt;ios()&lt;/code&gt; that enables both &lt;code&gt;iosArm64&lt;/code&gt; and &lt;code&gt;iOSX64&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, it's essential to optimize this setup, especially considering that building for unnecessary architectures can consume substantial time and resources. For example, even if your local development machine has an &lt;code&gt;ARM&lt;/code&gt; architecture, building the &lt;code&gt;X64&lt;/code&gt; framework unnecessarily adds to build times, and vice versa for other architectures.&lt;/p&gt;

&lt;p&gt;Generally speaking, if things work on one architecture, then it's high likely that it would work on other architectures too. So it's fine if you at least keep building only one architecture locally. One approach is to introduce a boolean flag in your gradle.properties file, creating custom logic to enable a specific iOS target.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Are you on a team where not everybody calling the Kotlin code wants or needs to build it locally? We've built &lt;a href="https://github.com/touchlab/KMMBridge"&gt;KMMBridge&lt;/a&gt;, a tool to help streamline the iOS dev flow in KMP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Be Careful with Custom Gradle Tasks
&lt;/h2&gt;

&lt;p&gt;While creating custom Gradle tasks might seem like a convenient way to handle common requirements, it's crucial to exercise caution, especially in a multi-module setup. In our experience, some custom tasks had unintended consequences on build times.&lt;/p&gt;

&lt;p&gt;For instance, we had custom tasks responsible for copying resources to another folder, but they ran across all modules, resulting in a noticeable slowdown during the build. To address this issue, we reconsidered our approach and opted for a different strategy to achieve the desired outcome without compromising build efficiency.&lt;/p&gt;

&lt;p&gt;The key takeaway is to ensure that custom tasks are appropriately configured to avoid unnecessary repetition across modules or tasks&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep build tools up-to-date
&lt;/h2&gt;

&lt;p&gt;Always stay current with Android Studio, Android Gradle Plugin, and Gradle itself. Each iteration brings improvements, potentially enhancing build speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AGP 8.+&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upgrade to Android Gradle Plugin 8.0.0 for default behaviors that optimize builds (i.e. &lt;a href="https://developer.android.com/build/optimize-your-build#use-non-transitive-r-classes"&gt;non-transitive R classes&lt;/a&gt;), especially for apps with multiple modules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuration Cache&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Newer build tools have better support for configuration cache. It seems like a very promising feature that can drastically improve build speeds in certain cases.&lt;/p&gt;

&lt;p&gt;While configuration cache is a promising feature for faster builds, ensure compatibility with all your tools. As of Kotlin 1.9.10, the Kotlin Multiplatform plugin still lacks full support, limiting its effectiveness.&lt;/p&gt;

&lt;p&gt;Kotlin 1.9.20 is supposed to being &lt;a href="https://kotlinlang.org/docs/whatsnew-eap.html#full-support-for-the-gradle-configuration-cache-in-kotlin-multiplatform"&gt;full support&lt;/a&gt; for configuration cache. We're pretty pumped about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Considerations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ensure Gradle &lt;a href="https://docs.gradle.org/current/userguide/build_cache.html"&gt;Build Cache&lt;/a&gt; is enabled.&lt;/li&gt;
&lt;li&gt;Amount of code can be overwhelming in Gradle files with multi-module setup. Simplify Gradle scripts using the &lt;a href="https://docs.gradle.org/current/userguide/custom_plugins.html#sec:precompiled_plugins"&gt;Gradle convention plugin&lt;/a&gt; to minimize duplicate configuration.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;By following these steps, you may turbocharge your Gradle builds, regardless of the project size or complexity. Happy coding! Let me know in the comments if you have questions. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid"&gt;@shaktiman_droid&lt;/a&gt; on Twitter, &lt;a href="https://www.linkedin.com/in/shaktiman-droid/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://slack.kotlinlang.org/"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>gradle</category>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Jetpack Compose: A use case for view interop migration strategy</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 13 Feb 2023 17:59:33 +0000</pubDate>
      <link>https://forem.com/touchlab/jetpack-compose-a-use-case-for-view-interop-migration-strategy-4dba</link>
      <guid>https://forem.com/touchlab/jetpack-compose-a-use-case-for-view-interop-migration-strategy-4dba</guid>
      <description>&lt;h2&gt;
  
  
  Approach
&lt;/h2&gt;

&lt;p&gt;Recently, we had an opportunity to redesign the sample app for an SDK we're developing. We were only redesigning one screen (home page), so we decided to introduce &lt;code&gt;Jetpack Compose&lt;/code&gt; in the app.&lt;/p&gt;

&lt;p&gt;Based on what we read, most migration or view interop posts are about keeping &lt;code&gt;Fragments&lt;/code&gt; and &lt;code&gt;fragment navigation&lt;/code&gt; as they are and moving the content of the fragments into &lt;code&gt;ComposeView&lt;/code&gt;. In fact, &lt;a href="https://developer.android.com/jetpack/compose/interop/migration-strategy" rel="noopener noreferrer"&gt;official docs also mention that strategy.&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;For that, we would still have to touch other fragments in the app rather than just the home page. So it felt like more work than what we intended to do. On top of that, the sample app extensively uses &lt;code&gt;PreferenceFragmentCompat&lt;/code&gt; for various setting screens. To move its content to &lt;code&gt;ComposeView&lt;/code&gt;, we would have to re-create a kind of preferences screen from scratch because compose doesn't have a straight replacement for &lt;code&gt;PreferenceFragment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So we decided to go with the &lt;a href="https://developer.android.com/jetpack/compose/interop/interop-apis#fragments-in-compose" rel="noopener noreferrer"&gt;Fragments in Compose&lt;/a&gt; approach. Along with that, we also moved our navigation using &lt;a href="https://developer.android.com/jetpack/compose/navigation" rel="noopener noreferrer"&gt;compose navigation component&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fragments in Compose
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Layout
&lt;/h3&gt;

&lt;p&gt;We created new layout files for each fragment with &lt;a href="https://developer.android.com/reference/androidx/fragment/app/FragmentContainerView" rel="noopener noreferrer"&gt;FragmentContainerView&lt;/a&gt; in each.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;androidx.fragment.app.FragmentContainerView&lt;/span&gt; &lt;span class="na"&gt;xmlns:android=&lt;/span&gt;&lt;span class="s"&gt;"http://schemas.android.com/apk/res/android"&lt;/span&gt;
    &lt;span class="na"&gt;android:id=&lt;/span&gt;&lt;span class="s"&gt;"@+id/fragment_container_view_events"&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"com.example.fragment.analytics.AnalyticsEventsFragment"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_width=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;
    &lt;span class="na"&gt;android:layout_height=&lt;/span&gt;&lt;span class="s"&gt;"match_parent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/androidx.fragment.app.FragmentContainerView&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Composable
&lt;/h3&gt;

&lt;p&gt;We wrote a generic &lt;code&gt;FragmentHolder&lt;/code&gt; composable with &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/ui/viewinterop/package-summary#AndroidViewBinding(kotlin.Function3,androidx.compose.ui.Modifier,kotlin.Function1)" rel="noopener noreferrer"&gt;AndroidViewBinding&lt;/a&gt;. It composes an Android layout resource. The layout files we created above would have their &lt;code&gt;Binding&lt;/code&gt; class generated that we can inflate and pass as &lt;code&gt;BindingFactory&lt;/code&gt; in the &lt;code&gt;AndroidViewBinding&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewBinding&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;FragmentHolderScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;topBarTitle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;androidViewBindingFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inflater&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LayoutInflater&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attachToParent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;onBackPress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
    &lt;span class="n"&gt;androidViewBindingUpdate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;.()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;topBar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;TopBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;topBarTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;onBackPress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onBackPress&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;paddingValues&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="nc"&gt;AndroidViewBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;androidViewBindingFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;paddingValues&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;androidViewBindingUpdate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Navigation
&lt;/h3&gt;

&lt;p&gt;After creating the composable, we defined a navigation component with a &lt;code&gt;Screen&lt;/code&gt; enum.&lt;/p&gt;

&lt;p&gt;With above defined layout binding and &lt;code&gt;FragmentHolderScreen&lt;/code&gt; for &lt;code&gt;AnalyticsEventsFragment&lt;/code&gt;, the minimized &lt;code&gt;Scaffold&lt;/code&gt; composables look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Scaffold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;contentPadding&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="nc"&gt;NavHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;navController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;startDestination&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;contentPadding&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;composable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;FragmentHolderScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;topBarTitle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toolbar_title_events&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                    &lt;span class="n"&gt;androidViewBindingFactory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ComposeFragmentEventsBinding&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;inflate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;androidViewBindingUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fragmentContainerViewEvents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getFragment&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;AnalyticsEventsFragment&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                            &lt;span class="c1"&gt;// Reference of AnalyticsEventsFragment is available here&lt;/span&gt;
                        &lt;span class="p"&gt;}&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                    &lt;span class="n"&gt;onBackPress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                        &lt;span class="nf"&gt;onBackPress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inner/child fragments
&lt;/h3&gt;

&lt;p&gt;Some of our fragments internally had navigation where a user would go to child fragments. While doing the compose-based navigation, we added those child fragments as part of our &lt;code&gt;Screen/route&lt;/code&gt; enum. Then, we set a lambda function (&lt;code&gt;val navigateTo: (Screen) -&amp;gt; Unit&lt;/code&gt;) in the &lt;code&gt;base&lt;/code&gt; fragment class to handle the click actions to move to child fragments.&lt;/p&gt;

&lt;h2&gt;
  
  
  SharedPreferences
&lt;/h2&gt;

&lt;p&gt;The sample app uses &lt;code&gt;SharedPreferences&lt;/code&gt;, and we didn't have time to move to something like &lt;code&gt;DataStore&lt;/code&gt;. It still worked out well after moving one screen to &lt;code&gt;Compose&lt;/code&gt;. We just made sure to define the reference of &lt;code&gt;SharedPreferences&lt;/code&gt; in &lt;code&gt;onCreate&lt;/code&gt; of the main activity and then pass the reference down to composable. Since we didn't touch existing fragments, they use the &lt;code&gt;SharedPreferences&lt;/code&gt; as defined already.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI Testing
&lt;/h2&gt;

&lt;p&gt;We have extensive UI testing in the sample app that tests the SDK. After moving the sample app's home screen to &lt;code&gt;Compose&lt;/code&gt;, we broke the entry point of all our tests.&lt;/p&gt;

&lt;p&gt;Luckily, compose UI testing and espresso testing work well with each other. You can write a compose test in one-line testing the compose-based screen, and the second line can be an espresso test step looking at the view layer.&lt;/p&gt;

&lt;p&gt;The biggest problem we faced around updating unit tests was the delay between the two systems. After clicking on a button on the compose-based screen, the app would go to SDK (a view-based UI). Many tests failed because the view would not be available on the screen when a test executes. After trying out several things, nothing worked well except adding &lt;code&gt;Thread.sleep()&lt;/code&gt; just before and after we handle button clicks on the compose-based screen. The delay probably gave espresso enough time to find the correct view-based screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Overall, we're satisfied with how the whole experiment went. We learned a bit about compose-view interop and got the opportunity to share our findings via this blog post.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid" rel="noopener noreferrer"&gt;@shaktiman_droid&lt;/a&gt; on Twitter, &lt;a href="https://www.linkedin.com/in/shaktiman-droid/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://slack.kotlinlang.org/" rel="noopener noreferrer"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/" rel="noopener noreferrer"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>music</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>KMM: A Use case for common UI behavior</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 30 Jan 2023 20:03:37 +0000</pubDate>
      <link>https://forem.com/touchlab/kmm-a-use-case-for-common-ui-behavior-2mi3</link>
      <guid>https://forem.com/touchlab/kmm-a-use-case-for-common-ui-behavior-2mi3</guid>
      <description>&lt;p&gt;This post demonstrates how we used &lt;code&gt;common&lt;/code&gt; KMP code for a common UI feature across three platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirement
&lt;/h2&gt;

&lt;p&gt;Recently, we got a new feature requirement for the SDK we're developing using Kotlin Multiplatform (KMP). The SDK has a typical UI form with a variety of fields in it that the user fills out. One of the fields is a &lt;code&gt;phone number&lt;/code&gt; field. The requirement was to auto-format the number as the user types it out. The end behavior would be like this,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cezytcreny6f88o0rmj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cezytcreny6f88o0rmj.gif" alt="GIF shows phone number typed and deleted in an input field"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How we did it initially
&lt;/h2&gt;

&lt;p&gt;We usually divide KMP work based on UI stories for each platform and a task for any required work in the &lt;code&gt;commonMain&lt;/code&gt; layer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For deeper dive into how we divide KMP work, checkout &lt;a href="https://dev.to/touchlab/dividing-kotlin-multiplatform-work-in-teams-2cad"&gt;Kevin's post&lt;/a&gt; about it&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Following the same approach, first, we added a couple of utility methods in &lt;code&gt;common&lt;/code&gt; code to &lt;code&gt;format&lt;/code&gt; and &lt;code&gt;unformat&lt;/code&gt; the phone number.&lt;/p&gt;

&lt;h3&gt;
  
  
  commonMain
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;formatPhoneNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// return formatted number using regex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;unformatPhoneNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CharSequence&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// return unformatted number using regex&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we worked on individual platform UI implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Android
&lt;/h3&gt;

&lt;p&gt;We implemented a custom &lt;a href="https://developer.android.com/reference/android/text/TextWatcher" rel="noopener noreferrer"&gt;TextWatcher&lt;/a&gt; and handled the logic in &lt;code&gt;beforeTextChanged&lt;/code&gt; and &lt;code&gt;afterTextChanged&lt;/code&gt; methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  iOS
&lt;/h3&gt;

&lt;p&gt;On iOS, we used &lt;code&gt;@objc func textFieldDidChange(_ sender: UITextField)&lt;/code&gt; to handle formatting while entering the number entering, and &lt;code&gt;func textField()&lt;/code&gt; with the &lt;code&gt;shouldChangeCharactersIn&lt;/code&gt; option to format the number when deleting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Web
&lt;/h3&gt;

&lt;p&gt;On ReactJS, we used &lt;code&gt;onChange&lt;/code&gt; of the &lt;code&gt;TextField&lt;/code&gt; to implement custom logic for formatting.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked and what went wrong
&lt;/h2&gt;

&lt;p&gt;What worked was that each platform performed the same for the general use case of entering and deleting the number due to having common knowledge and JIRA tickets for them.&lt;/p&gt;

&lt;p&gt;What differed between each platform was how the individual developer approached edge cases around entering and deleting the input from a specific cursor position.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For example, consider the input like this &lt;code&gt;(123) 456-7890&lt;/code&gt;. Now user wants to remove the number &lt;code&gt;6&lt;/code&gt; and manually sets the cursor position after the &lt;code&gt;dash(-)&lt;/code&gt; like this &lt;code&gt;(123) 456-|7890&lt;/code&gt;. Once the user presses the delete key, the number &lt;code&gt;6&lt;/code&gt; should be removed, and the new cursor should get positioned after the number 5 like this &lt;code&gt;(123) 45|7-890&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This logic got more complex as we found more and more edge cases at different cursor positions.&lt;/p&gt;

&lt;p&gt;What went wrong with our approach was that we started fixing these edge cases on each platform because each had unique bugs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;common&lt;/code&gt; code at the rescue
&lt;/h2&gt;

&lt;p&gt;While fixing those edge cases on each platform, we noticed a pattern in all implementations. We were ultimately doing some string manipulation based on the current cursor position to determine a new string to show on the screen along with the new cursor position.&lt;/p&gt;

&lt;p&gt;We realized an opportunity to combine the logic in &lt;code&gt;common&lt;/code&gt; code by just introducing methods that would take existing text and cursor position as inputs and provide a new string and a cursor position back.&lt;/p&gt;

&lt;p&gt;After doing a refactoring exercise for that, we came up with two methods,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * @param lastCursorIndex 0-based index
 */&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getTextAndCursorPositionOnTelephoneEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;lastCursorIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;newText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;TelephoneFormattingResult&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * @param deletedCharIndex 0-based index
 */&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getTextAndCursorPositionOnTelephoneDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;deletedCharIndex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;oldText&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;TelephoneFormattingResult&lt;/span&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TelephoneFormattingResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nd"&gt;@JsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@JsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cursorPosition"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;cursorPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It wasn't that straightforward to come up with the inputs for the methods above because all three platforms have different ways of getting cursor indices. While entering, the index of the last cursor position before entering the new character worked out well. For the deletion, the index of the deleted character worked out better.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;We learned that just because some feature is only UI related, we shouldn't jump to the conclusion that there won't be any &lt;code&gt;common&lt;/code&gt; code. &lt;/p&gt;

&lt;p&gt;In fact, for the feature mentioned in this post, in the end, we had the most crucial logic implemented in the &lt;code&gt;common&lt;/code&gt; code. Now, each platform's implementation remains bare-bones, where we use platform-specific APIs to extract existing text/position and rely on &lt;code&gt;common&lt;/code&gt; logic to determine new text and cursor position.&lt;/p&gt;

&lt;p&gt;As a bonus, we could write extensive unit tests for the &lt;code&gt;common&lt;/code&gt; logic to cover all the edge cases. On top of that, we would have only one implementation to modify if we ever decide to change the functionality of this feature or find a bug.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid" rel="noopener noreferrer"&gt;@shaktiman_droid&lt;/a&gt; on Twitter, &lt;a href="https://www.linkedin.com/in/shaktiman-droid/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://slack.kotlinlang.org/" rel="noopener noreferrer"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/" rel="noopener noreferrer"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>ux</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Samples of Using KMMBridge</title>
      <dc:creator>Michael Friend</dc:creator>
      <pubDate>Wed, 30 Nov 2022 20:46:11 +0000</pubDate>
      <link>https://forem.com/touchlab/samples-of-using-kmmbridge-4bha</link>
      <guid>https://forem.com/touchlab/samples-of-using-kmmbridge-4bha</guid>
      <description>&lt;h2&gt;
  
  
  What is KMM Bridge?
&lt;/h2&gt;

&lt;p&gt;KMMBridge is a Gradle plugin by Touchlab that aims to simplify the process of pushing a Kotlin Multiplatform SDK binary to a remote repo to allow iOS developers to use the shared SDK without installing the Kotlin toolchain or building the Kotlin code on every app build.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is this Sample?
&lt;/h2&gt;

&lt;p&gt;This sample project showcases our typical project setup for adding Kotlin Multiplatform Mobile code to existing separate Android and iOS apps using KMMBridge. We keep the Android app and the shared code in the same repo and keep the code to an absolute minimum with no dependencies so the project will build faster to speed things up when playing around with custom publish config. To see how to set up a project that keeps the Android app in a separate repo and uses a more realistic structure in shared code, check out the article &lt;a href="https://touchlab.co/quick-start-with-kmmbridge-1-hour-tutorial/" rel="noopener noreferrer"&gt;Quickstart Guide to KMMBridge&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Repos
&lt;/h2&gt;

&lt;p&gt;The basic KMMBridge sample is split into four repos rather than being a monorepo to emulate the trend we've seen from teams adopting KMM into existing apps by publishing a KMM library from one repo for iOS apps in other repos to consume. &lt;br&gt;
The four repos are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/touchlab/KMMBridgeSampleKotlin" rel="noopener noreferrer"&gt;KMMBridgeSampleKotlin&lt;/a&gt; aka &lt;code&gt;Kotlin Repo&lt;/code&gt; - This is the Kotlin repo with the shared SDK code as well as an Android app that uses it. &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/touchlab/KMMBridgeSampleCocoaPods" rel="noopener noreferrer"&gt;KMMBridgeSampleCocoaPods&lt;/a&gt; aka &lt;code&gt;CocoaPods Repo&lt;/code&gt;- a repo that pulls down the sdk with CocoaPods to use in an iOS app&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/touchlab/KMMBridgeSampleCocoaPods" rel="noopener noreferrer"&gt;KMMBridgeSampleSpm&lt;/a&gt; aka &lt;code&gt;SPM Repo&lt;/code&gt; - a repo that pulls down the sdk with Swift Package Manager to use in an iOS app&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/touchlab/PublicPodspecs" rel="noopener noreferrer"&gt;PublicPodspecs&lt;/a&gt; aka &lt;code&gt;Podspec Repo&lt;/code&gt; - A CocoaPods custom Podspec repo. When publishing for CocoaPods a podspec file will be pushed to this repo in a folder with the version number. See the CocoaPods section for more info on this. &lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  KMMBridgeSampleKotlin - The Kotlin Code
&lt;/h2&gt;

&lt;p&gt;This repo demonstrates the usual first step for a larger team that wants to try out Kotlin Multiplatform: putting new or existing Kotlin code in a &lt;code&gt;shared&lt;/code&gt; module in your Android app repo. This repo also has a standard Android &lt;code&gt;app&lt;/code&gt; module&lt;br&gt;
that depends on the shared code through a Gradle project dependency. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;shared&lt;/code&gt; module is a Kotlin Multiplatform module and targets &lt;code&gt;android&lt;/code&gt;, &lt;code&gt;ios&lt;/code&gt;, and &lt;code&gt;iosSimulatorArm64&lt;/code&gt;; declared in the &lt;code&gt;kotlin&lt;/code&gt; block of the &lt;code&gt;build.gradle.kts&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;kmmbridge&lt;/code&gt; config block, we set publishing both with both Swift Package Manager and Cocoapods. For your project you can just include one or the other based on your team's needs. It also uses &lt;code&gt;githubReleaseVersions&lt;/code&gt; to autoincrement versions when publishing a framework. Look over &lt;a href="https://touchlab.github.io/KMMBridge/general/CONFIGURATION_OVERVIEW" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; for more configuration options.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;addGithubPackagesRepository&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;kmmbridge&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;mavenPublishArtifacts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;githubReleaseVersions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;spm&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;cocoapods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"git@github.com:touchlab/PublicPodspecs.git"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;versionPrefix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.6"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Publishing Changes to Kotlin Code
&lt;/h3&gt;

&lt;p&gt;Since this publishes frameworks to our GitHub org, you'll need to fork the repo in order to publish changes. If you're only &lt;br&gt;
using SPM and remove the CocoaPods publishing, this should be enough to start publishing your changes. If you want to use &lt;br&gt;
CocoaPods you'll also need to fork the &lt;a href="https://github.com/touchlab/PublicPodspecs" rel="noopener noreferrer"&gt;Podspec Repo&lt;/a&gt; and change the URL passed to the &lt;code&gt;cocoapods(...)&lt;/code&gt; config above to your repo. You'll also have to set up deploy keys as secrets in your KMM repo. &lt;a href="https://touchlab.github.io/KMMBridge/cocoapods/COCOAPODS_GITHUB_PODSPEC" rel="noopener noreferrer"&gt;See Here&lt;/a&gt; for instructions on that.&lt;/p&gt;

&lt;p&gt;Once these steps are done you should be able to publish a new version of the SDK by manually running the publish job by going to the &lt;code&gt;Actions&lt;/code&gt; tab, selecting, &lt;code&gt;KMM Bridge Publish Release&lt;/code&gt; and clicking &lt;code&gt;Run workflow&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkhs02ire6fd1676cx6t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffkhs02ire6fd1676cx6t.png" alt="run workflow" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Using KMM Code from iOS
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Configure Access
&lt;/h3&gt;

&lt;p&gt;To pull down the binary and build your iOS app you'll need to configure authentication with GitHub Packages. This can either be done in your &lt;code&gt;~/.netrc&lt;/code&gt; file or through Mac's Keychain Access.&lt;/p&gt;

&lt;p&gt;Either way you'll need to generate a GitHub Personal Access Token (PAT) with repo access and &lt;code&gt;read:packages&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzkl9syvt0crnbe7rei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8bzkl9syvt0crnbe7rei.png" alt="pataccess" width="800" height="667"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you get a PAT string from that, create or open &lt;code&gt;~/.netrc&lt;/code&gt; and add this with your username and the PAT that was created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;machine maven.pkg.github.com
  login &lt;span class="o"&gt;[&lt;/span&gt;your username]
  password &lt;span class="o"&gt;[&lt;/span&gt;your PAT]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to use Mac's keychain to manage access, check out &lt;a href="https://medium.com/geekculture/xcode-13-3-supports-spm-binary-dependency-in-private-github-release-8d60a47d5e45" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt; for more details on setting that up.&lt;/p&gt;

&lt;h3&gt;
  
  
  SPM
&lt;/h3&gt;

&lt;p&gt;Since the base KMM repo is public, you should be able to clone &lt;a href="https://github.com/touchlab/KMMBridgeSampleSpm" rel="noopener noreferrer"&gt;the spm sample repo&lt;/a&gt; and run it. When you build the app it will look at the &lt;code&gt;Package.swift&lt;/code&gt; file in the root of the Kotlin module to get the url &lt;br&gt;
for the most recent version of the SDK then it will download the framework from that URL and include it in the project's build.&lt;/p&gt;
&lt;h4&gt;
  
  
  Getting Remote Changes
&lt;/h4&gt;

&lt;p&gt;To get changes to the Kotlin code you made in your fork of the repo, you'll have to change the SPM dependency to that repo.&lt;br&gt;
To do this first remove the existing dependency by selecting the project, clicking &lt;code&gt;Package Dependencies&lt;/code&gt;, clicking the package, and hitting the minus button. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60x7ioqcgw8pv5wkx8g7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F60x7ioqcgw8pv5wkx8g7.png" alt="delete spm package" width="800" height="140"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, add your repo as a new dependency by clicking the plus button, pasting your repo URL in the search bar, and clicking &lt;br&gt;
&lt;code&gt;Add Package&lt;/code&gt;. Double-check the version rules to make sure it will grab the version you want.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkofi7d9r0ca53ffabxf3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkofi7d9r0ca53ffabxf3.png" alt="add swift package" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you've already run the publish job in the Kotlin repo, SPM should pull the SDK in with your changes, assuming you selected the version correctly. If you publish a new version and want to pull it, you can right-click &lt;code&gt;shared&lt;/code&gt; in the sidebar and click &lt;code&gt;Update Package&lt;/code&gt; &lt;br&gt;
to pull in the most recent version. &lt;/p&gt;

&lt;p&gt;If you want to build the Kotlin code locally and test in the iOS app without publishing every change, check out &lt;a href="https://touchlab.github.io/KMMBridge/spm/IOS_LOCAL_DEV_SPM" rel="noopener noreferrer"&gt;this document&lt;/a&gt; on the SPM local dev flow.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cocoapods
&lt;/h3&gt;

&lt;p&gt;To run the CocoaPod based iOS app, clone &lt;a href="https://github.com/touchlab/KMMBridgeSampleCocoaPods.git" rel="noopener noreferrer"&gt;the sample repo&lt;/a&gt; and &lt;br&gt;
run &lt;code&gt;pod install&lt;/code&gt; in the root of the repo to download the SDK, then open the &lt;code&gt;xcworkspace&lt;/code&gt; file and run the app. &lt;code&gt;pod install&lt;/code&gt; will look in &lt;a href="https://github.com/touchlab/PublicPodspecs" rel="noopener noreferrer"&gt;https://github.com/touchlab/PublicPodspecs&lt;/a&gt; for a podspec matching the version specified in the &lt;code&gt;Podfile&lt;/code&gt; and &lt;br&gt;
download the framework it points to. &lt;/p&gt;
&lt;h4&gt;
  
  
  Getting Remote Changes
&lt;/h4&gt;

&lt;p&gt;To pull in changes you made to the Kotlin code with CocoaPods, you'll need to edit the &lt;code&gt;Podfile&lt;/code&gt; to point to the Podspec repo &lt;br&gt;
you created. Then run &lt;code&gt;pod update&lt;/code&gt; again and reopen your workspace file. We use &lt;code&gt;~&amp;gt; 0.6.0&lt;/code&gt; to tell CocoaPods to use the highest version above 0.6.0 up to but not including version 0.7.0. Since we set the version prefix to 0.6.0 in the &lt;code&gt;kmmbridge&lt;/code&gt; config and automatic versioning, every publish will get a new patch version for CocoaPods to recognize.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source '&amp;lt;YOUR PODSPEC REPO&amp;gt;'

target 'KMMBridgeSampleCocoaPods' do
  if ENV.include?("LOCAL_KOTLIN_PATH")
    pod 'shared', :path =&amp;gt; ENV["LOCAL_KOTLIN_PATH"]
  else
    pod 'shared', '~&amp;gt; 0.6.0'
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To build and test Kotlin changes locally with CocoaPods, check out &lt;a href="https://touchlab.github.io/KMMBridge/cocoapods/IOS_LOCAL_DEV_COCOAPODS" rel="noopener noreferrer"&gt;this doc&lt;/a&gt;&lt;br&gt;
on the CocoaPods local dev flow.&lt;/p&gt;

&lt;p&gt;If you have questions, don’t hesitate to reach out! You can head over to &lt;a href="https://kotlinlang.slack.com/archives/CTJB58X7X" rel="noopener noreferrer"&gt;#touchlab-tools&lt;/a&gt; on the kotlinlang Slack or fill out the &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;Contact Us&lt;/a&gt; form on the site. We look forward to hearing from you!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>frontend</category>
    </item>
    <item>
      <title>Introducing KMMBridge For Teams</title>
      <dc:creator>Touchlab</dc:creator>
      <pubDate>Mon, 10 Oct 2022 19:25:17 +0000</pubDate>
      <link>https://forem.com/touchlab/introducing-kmmbridge-for-teams-32ad</link>
      <guid>https://forem.com/touchlab/introducing-kmmbridge-for-teams-32ad</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Introducing KMMBridge for Teams&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Today we are announcing KMMBridge, part of Touchlab’s new Faktory&lt;sup id="fnref1"&gt;1&lt;/sup&gt; tooling suite. This set of build tools allows mobile teams to successfully publish shared code faster than ever with Kotlin Multiplatform Mobile.  Specifically targeted at iOS publishing, teams can now implement the Internal SDK Flow approach, today’s best practice to quickly integrate KMM into production app builds. To try it for yourself, visit &lt;a href="https://github.com/touchlab/KMMBridge" rel="noopener noreferrer"&gt;https://github.com/touchlab/KMMBridge&lt;/a&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;KMMBridge allows teams to publish and integrate Kotlin Multiplatform Mobile (KMM) Xcode Frameworks as an internal SDK.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;blockquote&gt;
&lt;p&gt;When you're ready, head to our &lt;a href="https://touchlab.co/quick-start-with-kmmbridge-1-hour-tutorial/" rel="noopener noreferrer"&gt;Quickstart Guide to KMMBridge&lt;/a&gt; to get started!   &lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Why We Built a Team-Focused Tool&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Touchlab has spent years working with teams at different stages of their Kotlin Multiplatform journey. Evaluating KMP, putting KMP into production, and yes, even a fair bit of time talking to teams who looked at KMP and decided against it. One of the key lessons we’ve learned seems obvious in retrospect.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Different types of teams work in different ways.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, every team is different. Every situation will be different. However, there are common patterns. Out of the box, the KMP and the Kotlin/Native toolkit will let you build an Xcode Framework, then integrate it locally into your Xcode project. This works well if everybody on the team builds Kotlin. And in an ideal world, everybody would be able to build Kotlin. But in the real world, most teams who have succeeded followed the Internal SDK Flow approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;The Internal SDK Flow Approach&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As with adopting any technology on a team, early wins help build momentum and confidence so the team can unlock the full potential over time. The Internal SDK Flow has emerged as the best practice to get faster ROI when adopting KMM. At its simplest, this approach means the Kotlin Xcode Framework is pre-built and published as an internal SDK (a private module shared with your team) so iOS developers can include it without building Kotlin locally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Kotlin Xcode Framework is pre-built and published as an internal SDK&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Somebody else (a team member, CI, etc.) builds the Kotlin Xcode Framework and publishes it somewhere internal. That Framework is then consumed by Xcode just like any other SDK. &lt;strong&gt;The iOS build workflow does not need to add Gradle or Kotlin and does not add to its build time or risk&lt;/strong&gt;. Our build tools let teams build their way immediately, increasing efficiency and eliminating unnecessary complexity to get started. For more context, see Nate Ebel’s talk from Droidcon NYC 2022: &lt;a href="https://www.droidcon.com/2022/09/29/adopting-kotlin-multiplatform-in-brownfield-applications/" rel="noopener noreferrer"&gt;Adopting Kotlin Multiplatform in Brownfield Applications&lt;/a&gt;. It's a very good overview of the startup issues teams face.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How KMMBridge Works&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;KMMBridge is a set of Gradle tools that integrate with your Kotlin Multiplatform Mobile project to assist with building and publishing KMM Xcode Frameworks. It is built for the Internal SDK Flow, but you can also use it to publish public SDKs as well. The basic flow is as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; Edit and test your shared Kotlin code, then push to your source control repo&lt;/li&gt;
&lt;li&gt; Kick off a CI build with KMMBridge. It packages, versions, and publishes your Xcode Framework&lt;/li&gt;
&lt;li&gt; Tell Xcode to update to the new version&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;The iOS build workflow does not need to add Gradle or Kotlin and  does not add to its build time or risk&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fty0pcbq01l5kja6py5lu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fty0pcbq01l5kja6py5lu.png" alt="KMMBridge supports Cocoapods and Swift Package Manager"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For iOS devs, there is no need to install or learn anything new. KMMBridge supports Cocoapods and Swift Package Manager. It can publish to a few different back ends out of the box, including Github Releases, with more support coming soon.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why Use This Approach?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As a leader or a member of a mid-sized-plus mobile team, does any of this sound familiar?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Most of the Android devs don’t know much about iOS builds&lt;/li&gt;
&lt;li&gt;  Most of the iOS devs have never touched Gradle&lt;sup id="fnref2"&gt;2&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;  The apps are in separate repos or at least have very different build workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every team that Touchlab has worked with, that has successfully added KMP to their existing iOS app, has started with an internal SDK flow.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some teams have relatively sophisticated internal module-sharing systems, Artifactory or similar. Most (and you’d be surprised at who) have nothing like that. Even with some kind of artifact sharing in place, there is a lot of custom work that would need to be done to wire up Kotlin Xcode Frameworks to be included into a production iOS build.&lt;/p&gt;

&lt;p&gt;KMMBridge will help most teams speed past this and get started productively with KMM.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Comes After the Internal SDK Flow?
&lt;/h2&gt;

&lt;p&gt;What is the next step when you want to scale and get shared code closer to your feature dev flow? &lt;/p&gt;

&lt;p&gt;It can seem simple on the surface but this can get tricky, depending on team structure and how features are developed. One example we’ve seen a bit of: over time &lt;strong&gt;both&lt;/strong&gt; teams could start to edit the code as if it wasn’t shared, and without clear guidance those edits can start to conflict in multiple ways.&lt;/p&gt;

&lt;p&gt;Most teams with Kotlin Multiplatform Mobile in production have used one or more Touchlab solutions. If you are looking to scale your KMM dev (or have already done so), &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;we should chat&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When you're ready, head to our &lt;a href="https://touchlab.co/quick-start-with-kmmbridge-1-hour-tutorial/" rel="noopener noreferrer"&gt;Quickstart Guide to KMMBridge&lt;/a&gt; to get started!&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;There is more to the Faktory tooling that is in the works, but we decided to carve out this bit now as it is a necessary entry point for teams adopting KMM. As KMM enters Beta, for continued growth and adoption, there are core capabilities that simply need to exist, and the internal SDK flow is one of them._ ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Most Android devs try to avoid it, me included (no offense Gradle)_ ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
    </item>
    <item>
      <title>Different ways to distribute and integrate Kotlin/JS library</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 11 Jul 2022 20:24:11 +0000</pubDate>
      <link>https://forem.com/touchlab/different-ways-to-distribute-and-integrate-kotlinjs-library-1hg3</link>
      <guid>https://forem.com/touchlab/different-ways-to-distribute-and-integrate-kotlinjs-library-1hg3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Note that examples in this post use &lt;a href="https://kotlinlang.org/docs/whatsnew17.html"&gt;Kotlin 1.7.0&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the previous &lt;a href="https://dev.to/touchlab/jsexport-guide-for-exposing-kotlin-to-js-20l9"&gt;post&lt;/a&gt; in the Kotlin/JS series, we learned about &lt;code&gt;@JsExport&lt;/code&gt; to expose Kotlin code on the JS side. Now, we would look at various ways to distribute a JS library code through a KMP setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Gradle Setup

&lt;ul&gt;
&lt;li&gt;Webpack&lt;/li&gt;
&lt;li&gt;
Node Module

&lt;ul&gt;
&lt;li&gt;npm-publish&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
Using the library

&lt;ul&gt;
&lt;li&gt;
Use webpack executable

&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
Use as node module

&lt;ul&gt;
&lt;li&gt;HTML&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Gradle Setup&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't already have a &lt;code&gt;JS&lt;/code&gt; target in your KMP library project, then you should check out &lt;a href="https://dev.to/touchlab/add-kotlinjs-support-to-your-kmm-library-48d9"&gt;this blog post&lt;/a&gt; first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's look at common options to use for &lt;code&gt;JS&lt;/code&gt; target,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;js&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;nodejs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;binaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;library&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;binaries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;browser()&lt;/strong&gt;&lt;br&gt;
It sets the JavaScript target execution environment as &lt;code&gt;browser&lt;/code&gt;. It provides a Gradle task—&lt;code&gt;jsBrowserTest&lt;/code&gt; that runs all &lt;code&gt;js&lt;/code&gt; tests inside the browser using &lt;code&gt;karma&lt;/code&gt; and &lt;code&gt;webpack&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;nodejs()&lt;/strong&gt;&lt;br&gt;
It sets the JavaScript target execution environment as &lt;code&gt;nodejs&lt;/code&gt;. It provides a Gradle task—&lt;code&gt;jsNodeTest&lt;/code&gt; that runs all &lt;code&gt;js&lt;/code&gt; tests inside &lt;code&gt;nodejs&lt;/code&gt; using the built-in test framework.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;binaries.library()&lt;/strong&gt;&lt;br&gt;
It tells the Kotlin compiler to produce Kotlin/JS code as a distributable node library. Depending on which target you've used along with this, you would get Gradle tasks to generate library distribution files.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Kotlin browser tasks
&lt;span class="nt"&gt;--------------------&lt;/span&gt;
jsBrowserDevelopmentLibraryDistribution
jsBrowserDevelopmentLibraryPrepare
jsBrowserProductionLibraryDistribution
jsBrowserProductionLibraryPrepare

Kotlin node tasks
&lt;span class="nt"&gt;-----------------&lt;/span&gt;
jsNodeDevelopmentLibraryDistribution
jsNodeDevelopmentLibraryPrepare
jsNodeDevelopmentRun
jsNodeProductionLibraryDistribution
jsNodeProductionLibraryPrepare
jsNodeProductionRun
jsNodeRun
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Either&lt;code&gt;jsBrowserProductionLibraryDistribution&lt;/code&gt; or &lt;code&gt;jsNodeProductionLibraryDistribution&lt;/code&gt; task generates output files in &lt;code&gt;&amp;lt;YourLibModule&amp;gt;/build/productionLibrary&lt;/code&gt; folder&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;binaries.executable()&lt;/strong&gt;&lt;br&gt;
It tells the Kotlin compiler to produce Kotlin/JS code as webpack executable &lt;code&gt;.js&lt;/code&gt; files. Enabling this option generates the following Gradle tasks with the &lt;code&gt;browser()&lt;/code&gt; environment.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jsBrowserDevelopmentExecutableDistributeResources
jsBrowserDevelopmentExecutableDistribution
jsBrowserDevelopmentRun - start development webpack dev server
jsBrowserDevelopmentWebpack - build webpack development bundle
jsBrowserDistribution
jsBrowserProductionExecutableDistributeResources
jsBrowserProductionRun - start production webpack dev server
jsBrowserProductionWebpack - build webpack production bundle
jsBrowserRun
jsBrowserWebpack
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Task &lt;code&gt;jsBrowserDistribution&lt;/code&gt; generates webpack bundle &lt;code&gt;js&lt;/code&gt; file along with &lt;code&gt;.map&lt;/code&gt; file in &lt;code&gt;&amp;lt;YourLibModule&amp;gt;/build/distributions&lt;/code&gt; folder.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Webpack&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Webpack is a &lt;a href="https://webpack.js.org/"&gt;JS bundler tool&lt;/a&gt;. It allows the creation of a single executable JS file combining all the dependencies.&lt;/p&gt;

&lt;p&gt;As seen above in the Gradle setup section, you can output your &lt;code&gt;Kotlin/JS&lt;/code&gt; library as a single executable by using &lt;code&gt;browser()&lt;/code&gt; and &lt;code&gt;binaries.executable()&lt;/code&gt; options in &lt;code&gt;js(IR)&lt;/code&gt; target. By default, the bundle &lt;code&gt;.js&lt;/code&gt; file and exported library name are the same as the module name. For example, for a module named &lt;em&gt;shared&lt;/em&gt;, a &lt;code&gt;shared.js&lt;/code&gt; file gets generated. It would have &lt;code&gt;exports.shared=...&lt;/code&gt; that reflects the name of the library that one would use when consuming this library in a JS/TS app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....."object"==typeof exports?exports.shared=n().....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;browser()&lt;/code&gt; function provides a DSL that you can use to update &lt;a href="https://github.com/JetBrains/kotlin/blob/master/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/webpack/KotlinWebpack.kt"&gt;KotlinWebpack&lt;/a&gt; task for various custom configurations. For example, you can change the file and library name as below,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;browser {
    webpackTask {
        outputFileName = "kmp_lib.js"
        output.library = "kmpLib"
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can explore more options on your own.&lt;/p&gt;

&lt;h3&gt;
  
  
  Node Module&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Kotlin/JS library can also be published as a node module, and installed via &lt;code&gt;npm&lt;/code&gt; in an app.&lt;/p&gt;

&lt;p&gt;As mentioned above in the Gradle setup section, when you run &lt;code&gt;jsNodeProductionLibraryDistribution&lt;/code&gt;, it generates the following &lt;code&gt;node-module&lt;/code&gt; related files,&lt;br&gt;
    - &lt;code&gt;.js&lt;/code&gt; file each for the library and all dependencies&lt;br&gt;
    - &lt;code&gt;.js.map&lt;/code&gt; file for each &lt;code&gt;.js&lt;/code&gt; file&lt;br&gt;
    - Typescript &lt;code&gt;.d.ts&lt;/code&gt; file&lt;br&gt;
    - &lt;code&gt;package.json&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note&lt;/em&gt; that node module cannot have upper case character in the name. An error or warning may appear if the module name has a capital character. We can declare a &lt;code&gt;moduleName&lt;/code&gt; in the &lt;code&gt;js(IR)&lt;/code&gt; target to avoid that,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;js(IR) {
    moduleName = "kmp-lib"
    ....
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;npm-publish&lt;/code&gt; plugin&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;By default, there is no quick way to publish the library output as a node module to maven.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mpetuska/npm-publish"&gt;npm-publish&lt;/a&gt; is a popular library by &lt;a href="https://twitter.com/MartynasPetuska"&gt;Martynas Petuška&lt;/a&gt; that helps with NPM publishing. It also provides various configuration options under the &lt;code&gt;npmPublish&lt;/code&gt; Gradle task.&lt;/p&gt;

&lt;p&gt;The plugin generates a tarball that we can use to install the library locally without publishing first. The &lt;code&gt;packJsPackage&lt;/code&gt; task also logs a readable output of tarball content and details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm notice 
npm notice 📦  shared@0.1.0
npm notice &lt;span class="o"&gt;===&lt;/span&gt; Tarball Contents &lt;span class="o"&gt;===&lt;/span&gt; 
npm notice 291B  kmp-lib.d.ts                     
npm notice 1.4kB kmp-lib.js                       
npm notice 205B  kmp-lib.js.map                   
npm notice 1.4kB kotlin-kotlin-stdlib-js-ir.js    
npm notice 551B  kotlin-kotlin-stdlib-js-ir.js.map
npm notice 95B   package.json                     
npm notice &lt;span class="o"&gt;===&lt;/span&gt; Tarball Details &lt;span class="o"&gt;===&lt;/span&gt; 
npm notice name:          shared                                  
npm notice version:       0.1.0                                   
npm notice filename:      shared-0.1.0.tgz                        
npm notice package size:  1.6 kB                                  
npm notice unpacked size: 3.9 kB                                  
shared-0.1.0.tgz
npm notice shasum:        c3c5e0a7a6d99cf1b7632fcfc4cef2e0b9052cb2
npm notice integrity:     sha512-dZa4uNPRMjyny[...]JjzzNAiP7abHw&lt;span class="o"&gt;==&lt;/span&gt;
npm notice total files:   6                                       
npm notice 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're planning to publish a &lt;code&gt;Kotlin/JS&lt;/code&gt; library as a node module, then this is a must-have plugin in your project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Using the library&lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We will now look at various ways to integrate the Kotlin/JS library into web applications.&lt;/p&gt;

&lt;p&gt;For example, we have a &lt;code&gt;Greeting&lt;/code&gt; class and a &lt;code&gt;greet()&lt;/code&gt; method under a package &lt;code&gt;jabbar.jigariyo.kmplibrary&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;jabbar.jigariyo.kmplibrary&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlin.js.JsExport&lt;/span&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello, JS!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use webpack executable&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We will now look at using the generated webpack binary executable bundle file in HTML and react JS app.&lt;/p&gt;

&lt;h4&gt;
  
  
  HTML&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We can simply embed the &lt;code&gt;js&lt;/code&gt; file as a script under the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag of the HTML body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Including a External JavaScript File&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Here I have copied the js file in the root folder of this html file --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"kmp_lib.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kmpLib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jabbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jigariyo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kmplibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two important things to note here are,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using the library name to get a reference &lt;code&gt;var kmpLib = this['kmpLib']&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Getting reference of &lt;code&gt;Greeting&lt;/code&gt; class using package name after the &lt;code&gt;library&lt;/code&gt; reference &lt;code&gt;kmpLib.jabbar.jigariyo.kmplibrary.Greeting()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the &lt;code&gt;html&lt;/code&gt; file is open in the browser, it would log &lt;code&gt;Hello, JS!&lt;/code&gt; in console output.&lt;/p&gt;

&lt;h4&gt;
  
  
  JavaScript&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;For the JavaScript example, I've a React app.&lt;/p&gt;

&lt;p&gt;To keep this simple, I've copied the &lt;code&gt;distributions&lt;/code&gt; folder in the &lt;code&gt;src&lt;/code&gt; directory of the React app.&lt;/p&gt;

&lt;p&gt;As the next step, import the &lt;code&gt;library&lt;/code&gt; module in the &lt;code&gt;App.js&lt;/code&gt; and use it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./distributions/kmp_lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;......&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jabbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jigariyo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kmplibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;.......&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we run the app, &lt;code&gt;Hello, JS!&lt;/code&gt; gets printed in the console and validates the integration with the library.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that you might have to deal with configuring &lt;code&gt;eslint&lt;/code&gt; if using React.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  TypeScript&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://tkdodo.eu/blog/calling-java-script-from-type-script"&gt;It's not straightforward&lt;/a&gt; to use just a &lt;code&gt;js&lt;/code&gt; file without typescript definitions in a &lt;code&gt;Typescript&lt;/code&gt; app.&lt;/p&gt;

&lt;p&gt;I have skipped this integration as it's out of scope for this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use as node module&lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;We will now look at installing and using the generated library files in a React JS and a TS app.&lt;/p&gt;

&lt;p&gt;To install the module locally, you can do &lt;code&gt;npm install &amp;lt;PATH&amp;gt;&lt;/code&gt;. You can either use the path to the tarball (&lt;code&gt;.tgz&lt;/code&gt;) file generated by the &lt;code&gt;npm-publish&lt;/code&gt; plugin or the relative path to the &lt;code&gt;build/productionLibrary&lt;/code&gt; folder of the kmp module.&lt;/p&gt;

&lt;p&gt;For example, the installation path for my sample looks like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install ../shared/build/productionLibrary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once installed, the &lt;code&gt;package.json&lt;/code&gt; would contain the library under the &lt;code&gt;dependencies&lt;/code&gt; section,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"kmp-lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file:../shared/build/productionLibrary"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note here that the &lt;code&gt;name&lt;/code&gt; is the same as the &lt;code&gt;moduleName&lt;/code&gt; we had defined earlier in the above &lt;code&gt;gradle-setup&lt;/code&gt; section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  HTML&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Using node module in plain HTML is out of scope for this post. There are techniques to make that work if you need to go that route.&lt;/p&gt;

&lt;h4&gt;
  
  
  JavaScript&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;We should be able to &lt;code&gt;import&lt;/code&gt; the library and use it once installed via &lt;code&gt;npm&lt;/code&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  App.js
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kmp-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;......&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jabbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jigariyo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kmplibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="p"&gt;.....&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we run the app, &lt;code&gt;Hello, JS!&lt;/code&gt; gets printed in the console and validates the integration with the library.&lt;/p&gt;

&lt;h4&gt;
  
  
  TypeScript&lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Just like the &lt;code&gt;JavaScript&lt;/code&gt; example above, you have a reference of the library available after &lt;code&gt;npm install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Importing in &lt;code&gt;Typescript&lt;/code&gt; is slightly different as seen below&lt;/p&gt;

&lt;h5&gt;
  
  
  main.ts
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kmp-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;kmpLib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jabbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jigariyo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kmplibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we run &lt;code&gt;tsc main.ts&lt;/code&gt; and then &lt;code&gt;node main.js&lt;/code&gt; commands in the terminal, we would see &lt;code&gt;Hello, JS!&lt;/code&gt; printed.&lt;/p&gt;




&lt;p&gt;In this post, we first learned how to distribute a Kotlin/JS library as either a webpack bundle or node module. We later learned how to integrate the library in HTML, JS, or a TS app.&lt;/p&gt;




&lt;p&gt;Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at &lt;a href="https://twitter.com/shaktiman_droid"&gt;@shaktiman_droid&lt;/a&gt; on Twitter, &lt;a href="https://www.linkedin.com/in/shaktiman-droid/"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://slack.kotlinlang.org/"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>javascript</category>
      <category>kotlinjs</category>
    </item>
    <item>
      <title>@JsExport guide for exposing Kotlin to JS</title>
      <dc:creator>Jigar Brahmbhatt</dc:creator>
      <pubDate>Mon, 14 Mar 2022 16:19:31 +0000</pubDate>
      <link>https://forem.com/touchlab/jsexport-guide-for-exposing-kotlin-to-js-20l9</link>
      <guid>https://forem.com/touchlab/jsexport-guide-for-exposing-kotlin-to-js-20l9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Note that this post focuses on JS output for Kotlin. There is also a Typescript output (.d.ts file) with some unique issues that this post doesn't cover in detail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the previous &lt;a href="https://dev.to/touchlab/add-kotlinjs-support-to-your-kmm-library-48d9"&gt;post&lt;/a&gt;, we added &lt;code&gt;Kotlin/JS&lt;/code&gt; support to an existing KMM library. Now, we would add code that works on the JS side.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table Of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
Usage

&lt;ul&gt;
&lt;li&gt;@ExperimentalJsExport vs @JsExport&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

Limitations

&lt;ul&gt;
&lt;li&gt;Collections&lt;/li&gt;
&lt;li&gt;Long&lt;/li&gt;
&lt;li&gt;
Interface

&lt;ul&gt;
&lt;li&gt;Solution - Using Implementation class&lt;/li&gt;
&lt;li&gt;Solution - Using Expect-Actual&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Enum&lt;/li&gt;

&lt;li&gt;Sealed classes&lt;/li&gt;

&lt;li&gt;Code mangling&lt;/li&gt;

&lt;li&gt;Suspended functions&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Usage &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It is critical to understand &lt;a href="https://kotlinlang.org/docs/js-to-kotlin-interop.html#jsexport-annotation" rel="noopener noreferrer"&gt;@JsExport&lt;/a&gt; annotation and all the issues around it if you expose Kotlin code through Kotlin/JS as an external JS library&lt;/p&gt;

&lt;p&gt;With the new &lt;a href="https://kotlinlang.org/docs/js-ir-compiler.html" rel="noopener noreferrer"&gt;IR compiler&lt;/a&gt;, &lt;strong&gt;Kotlin declarations do not get exposed to JavaScript by default&lt;/strong&gt;. To make Kotlin declarations visible to JavaScript, they &lt;strong&gt;must be&lt;/strong&gt; annotated with @JsExport.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that @JsExport is experimental as of the posted date of this post (with Kotlin 1.6.10)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s start with a very basic example,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// commonMain - Greeting.kt&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At this point, the generated &lt;code&gt;.js&lt;/code&gt; library file would not have any reference to the Greeting class. The reason is that it is missing the &lt;code&gt;@JsExport&lt;/code&gt; annotation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can generate JS library code via &lt;code&gt;./gradlew jsBrowserDistribution&lt;/code&gt;. You would find the &lt;code&gt;.js, .d.ts and map&lt;/code&gt; file in &lt;code&gt;root/build/js/packages/&amp;lt;yourlibname&amp;gt;/kotlin&lt;/code&gt; folder.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, add the annotation to generate JS code for it,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlin.js.ExperimentalJsExport&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;kotlin.js.JsExport&lt;/span&gt;

&lt;span class="nd"&gt;@ExperimentalJsExport&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Hello World!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;.js&lt;/code&gt; and &lt;code&gt;.d.ts&lt;/code&gt; files would now contain the Greeting reference.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generated .js file&lt;/strong&gt;
```javascript
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;function Greeting() {&lt;br&gt;
}&lt;br&gt;
Greeting.prototype.greeting = function () {&lt;br&gt;
  return 'Hello World!';&lt;br&gt;
};&lt;br&gt;
Greeting.$metadata$ = {&lt;br&gt;
  simpleName: 'Greeting',&lt;br&gt;
  kind: 'class',&lt;br&gt;
  interfaces: []&lt;br&gt;
};&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
- **Generated .d.ts file**
```typescript


export namespace jabbar.jigariyo.kmplibrary {
    class Greeting {
        constructor();
        greeting(): string;
    }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now you can call &lt;code&gt;Greeting&lt;/code&gt; from JavaScript&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;jabbar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jigariyo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kmplibrary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="c1"&gt;// Hello World!&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that you would have to use fully qualified Kotlin names in JavaScript because Kotlin exposes its &lt;a href="https://kotlinlang.org/docs/js-to-kotlin-interop.html#package-structure" rel="noopener noreferrer"&gt;package structure&lt;/a&gt; to JavaScript.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is &lt;strong&gt;important&lt;/strong&gt; to keep in mind that all public attributes in your exportable object would also need to be exportable.&lt;/p&gt;

&lt;p&gt;In the following example, &lt;code&gt;CustomObj&lt;/code&gt; would also need to be exportable to export &lt;code&gt;MyDataClass&lt;/code&gt;,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;MyDataClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;strVal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;customObj&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;CustomObj&lt;/span&gt; &lt;span class="c1"&gt;// This would need to be exportable&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  @ExperimentalJsExport vs @JsExport &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;@JsExport&lt;/code&gt; is the annotation you need to tell the compiler to generate JavaScript code, and &lt;code&gt;@ExperimentalJsExport&lt;/code&gt; is an opt-in marker annotation to use &lt;code&gt;@JsExport&lt;/code&gt; as it is experimental to use.&lt;/p&gt;

&lt;p&gt;You can get rid of the requirement of adding &lt;code&gt;@ExperimentalJsExport&lt;/code&gt; in code by declaring it as &lt;code&gt;OptIn&lt;/code&gt; in &lt;code&gt;languageSettings&lt;/code&gt; for all source sets in your &lt;code&gt;kotlin&lt;/code&gt; block.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nf"&gt;kotlin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;sourceSets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;all&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;languageSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;optIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"kotlin.js.ExperimentalJsExport"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  Limitations &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;As of Kotlin &lt;code&gt;1.6.10&lt;/code&gt;, there are heavy limitations on what Kotlin types one can export to JavaScript.&lt;/p&gt;

&lt;p&gt;You will most likely face one of these limitations if you add JS support in an existing KMP library.&lt;/p&gt;

&lt;p&gt;Whenever something is &lt;code&gt;not-exportable&lt;/code&gt;, you would get either an error or a warning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code does not compile with such errors
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdzqmbsmgtl56c4u4syww.png" alt="Js exportable error example"&gt;
&lt;/li&gt;
&lt;li&gt;Code compiles with such warnings, but you might have run-time issues
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7kzdox841kzdl4heqoj.png" alt="JS exportable warning"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Collections &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Kotlin's collections APIs are not exportable, so you would have to come up with different strategies to deal with them. Some examples would be:&lt;/p&gt;

&lt;h4&gt;
  
  
  Map
&lt;/h4&gt;

&lt;p&gt;You would have to remove &lt;code&gt;Map&lt;/code&gt; usage from &lt;code&gt;common&lt;/code&gt; code that also exports to JS, or you would have to have a different implementation on the &lt;code&gt;mobile&lt;/code&gt; and &lt;code&gt;js&lt;/code&gt; side. You can use the &lt;code&gt;kotlin.js.Json&lt;/code&gt; object on the &lt;code&gt;jsMain&lt;/code&gt; side and then map it to the &lt;code&gt;Kotlin&lt;/code&gt; map whenever needed.&lt;/p&gt;

&lt;p&gt;For JS specific implementation, you may also look into using &lt;a href="https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-js/src/main/kotlin/kotlinx/js/Record.kt" rel="noopener noreferrer"&gt;Record&lt;/a&gt; from &lt;a href="https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-js" rel="noopener noreferrer"&gt;kotlin-extensions&lt;/a&gt; library.&lt;/p&gt;

&lt;h4&gt;
  
  
  List
&lt;/h4&gt;

&lt;p&gt;You can replace the &lt;code&gt;List&lt;/code&gt; usage with an &lt;code&gt;Array&lt;/code&gt; to keep the same code for all platforms. It may or may not be a simple replacement.&lt;/p&gt;

&lt;p&gt;For example, &lt;code&gt;Array&lt;/code&gt; would work if only used in an object for parsing an API response. Note that having an &lt;code&gt;Array&lt;/code&gt; in a &lt;code&gt;Data&lt;/code&gt; class would require providing your own &lt;code&gt;equals&lt;/code&gt; and &lt;code&gt;hashcode&lt;/code&gt; implementations.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that moving from &lt;code&gt;List&lt;/code&gt; to &lt;code&gt;Array&lt;/code&gt; might have an impact on generated code for &lt;code&gt;iOS&lt;/code&gt;. &lt;code&gt;List&lt;/code&gt; becomes &lt;code&gt;NSArray&lt;/code&gt; on iOS side but &lt;code&gt;Array&lt;/code&gt; becomes a Kotlin object wrapping the array&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you want separate implementation for &lt;code&gt;jsMain&lt;/code&gt;, then &lt;code&gt;kotlin-extensions&lt;/code&gt; library provides some helpful JS specific classes like &lt;a href="https://github.com/JetBrains/kotlin-wrappers/tree/master/kotlin-js/src/main/kotlin/kotlinx/js" rel="noopener noreferrer"&gt;Iterator, Set, and ReadOnlyArray&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Long &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Long&lt;/code&gt; is not mapped to anything as there is no equivalent in the &lt;code&gt;JavaScript&lt;/code&gt; world. You would see the &lt;code&gt;non-exportable&lt;/code&gt; warning if you export &lt;code&gt;Long&lt;/code&gt; via &lt;code&gt;Kotlin&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you ignore the warning, then &lt;code&gt;Long&lt;/code&gt; still kinda works. It just takes any value from JS. Kotlin will receive the input as &lt;code&gt;Long&lt;/code&gt; if JavaScript code sends a &lt;code&gt;BigInt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It will not work for &lt;code&gt;Typescript&lt;/code&gt; unless you set &lt;code&gt;skipLibCheck = true&lt;/code&gt; in the config as type &lt;code&gt;kotlin.Long&lt;/code&gt; is not available.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Kotlin &lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeting&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NON_EXPORTABLE_TYPE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;printLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Generated .js&lt;/span&gt;
&lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;printLong&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Generated .d.ts&lt;/span&gt;
&lt;span class="nf"&gt;printLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kotlin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Long&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Usage from JS&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0b11111111111111111111111111111111111111111111111111111"&lt;/span&gt;
&lt;span class="nc"&gt;Greeting&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;printLong&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c1"&gt;// This works&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;You can use @Suppress("NON_EXPORTABLE_TYPE") to suppress the exportable warning&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Interface &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Kotlin interfaces are not exportable. It gets annoying when a library has an interface-driven design, where it exposes the interface in public API rather than a specific implementation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Interfaces will be exportable starting upcoming &lt;a href="https://youtrack.jetbrains.com/issue/KT-45434" rel="noopener noreferrer"&gt;Kotlin 1.6.20&lt;/a&gt;! We would have to play around with that to see it working.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are workarounds to make interfaces work on &lt;code&gt;JavaScript&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following are some examples for getting around interfaces:&lt;/p&gt;

&lt;h4&gt;
  
  
  Using Implementation Class &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The above code would show the non-exportable error. You can use the &lt;code&gt;interface&lt;/code&gt; indirectly via its implementation class to work around that problem.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HELLO from HelloInterface"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Generated JS code for the above &lt;code&gt;hello&lt;/code&gt; method will have a &lt;code&gt;mangled&lt;/code&gt; name. Read more about it in code-mangling section&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@JsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HELLO from HelloInterface"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Similarly, here are some variations to use &lt;code&gt;HelloInterface&lt;/code&gt;,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Variation (2)&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;HelloGet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getInterface&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Variation (3)&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWrapper&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@JsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Variation (4)&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;HelloWrapperData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;@JsName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;All above variations are usable from the &lt;code&gt;JS&lt;/code&gt; side even with a &lt;code&gt;non-exportable&lt;/code&gt; warning around interface usage,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="cm"&gt;/**
 * JS side calling code
 * (1)
 * Hello.hello()
 *
 * (2)
 * HelloGet.getInterface().hello()
 *
 * (3)
 * const wrapperObj = HelloWrapper(Hello)
 * wrapperObj.value.hello()
 *
 * (4)
 * const wrapperDataObj = HelloWrapperData(Hello)
 * wrapperDataObj.value.hello()
 */&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Using Expect-Actual Pattern &lt;a&gt;&lt;/a&gt;
&lt;/h4&gt;

&lt;p&gt;Another idea for using interfaces is to use the &lt;code&gt;expect-actual&lt;/code&gt; pattern to define a Kotlin interface in &lt;code&gt;common&lt;/code&gt; and &lt;code&gt;mobile&lt;/code&gt; platforms and define an &lt;code&gt;external interface&lt;/code&gt; for the JS side. This approach might not scale well but can be very useful for simple cases.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// commonMain&lt;/span&gt;
&lt;span class="n"&gt;expect&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// jsMain&lt;/span&gt;
&lt;span class="c1"&gt;// Here external makes it a normal JS object in generated code&lt;/span&gt;
&lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="k"&gt;external&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// mobileMain&lt;/span&gt;
&lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;Api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;actual&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;getProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;These examples showcase workarounds that might or might not work for a particular project. &lt;/p&gt;

&lt;h3&gt;
  
  
  Enum &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;As of Kotlin 1.6.10, enums are not exportable. It can create issues for projects that have a lot of existing enums. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Good news is that its support coming in Kotlin 1.6.20&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is also a trick to export and use enums on JS. It requires defining a JS-specific object with attributes that point to actual enums.&lt;/p&gt;

&lt;p&gt;For example, this code won't compile,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="nc"&gt;Gender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;MALE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nc"&gt;FEMALE&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Instead, you can do this indirectly by re-defining them through object fields. It works with a non-exportable warning. Note the warning suppression with annotation.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@Suppress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"NON_EXPORTABLE_TYPE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@ExperimentalJsExport&lt;/span&gt;
&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;GenderType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;male&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MALE&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;female&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Gender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FEMALE&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Sealed classes &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Sealed classes are exportable, but they’re buggy as of Kotlin 1.6.10&lt;/p&gt;

&lt;p&gt;You can export a data or regular class as subclasses inside a Sealed class body, but not an object. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Loading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// This won't be visible &lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// This would be visible&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can work around this problem by moving the subclasses outside the body of the sealed class, but then you cannot write it like &lt;code&gt;State.Loading&lt;/code&gt;. It is more of a readability issue in that case.&lt;/p&gt;

&lt;p&gt;Also, sealed classes have known issues with typescript binding as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code mangling &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;The Kotlin compiler mangles the names of the functions and attributes. It can be frustrating to deal with mangled names.&lt;/p&gt;

&lt;p&gt;For example,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@JsExport&lt;/span&gt;
&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;Hello&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;hello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HELLO from HelloInterface"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Generated JS code for &lt;code&gt;hello&lt;/code&gt; method looks like,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello_sv8swh_k$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HELLO from HelloInterface&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We would need to use the &lt;a href="https://kotlinlang.org/docs/js-to-kotlin-interop.html#jsname-annotation" rel="noopener noreferrer"&gt;@JsName&lt;/a&gt; annotation to provide a generated name. If you see numbers in attribute names like &lt;code&gt;_something_0, _value_3&lt;/code&gt; on the JS side, then it is a sign that you need to provide a controlled name via &lt;code&gt;@JsName&lt;/code&gt; annotation on the &lt;code&gt;Kotlin&lt;/code&gt; side.&lt;/p&gt;

&lt;p&gt;After adding &lt;code&gt;@JsName("hello")&lt;/code&gt; in the above example, generated code looks like this where there is a new &lt;code&gt;hello&lt;/code&gt; method that references &lt;code&gt;hello_sv8swh_k$&lt;/code&gt; internally,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello_sv8swh_k$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;HELLO from HelloInterface&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;Hello&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hello_sv8swh_k&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that &lt;code&gt;@JsName&lt;/code&gt; is prohibited for overridden members, so you would need to set it to a base class property or method.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Suspended functions &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;You cannot expose suspended functions to JS. You would need to convert them into &lt;code&gt;JavaScript Promise&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;The easiest way to do that would be to wrap suspend calls inside,&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

GlobalScope.promise {
  // suspend call
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;This function comes from &lt;code&gt;Promise.kt&lt;/code&gt; in the &lt;code&gt;coroutine library&lt;/code&gt;. It returns a generic type.&lt;/p&gt;




&lt;p&gt;As mentioned earlier, some of these issues would get resolved with Kotlin 1.6.20, so keep that in mind.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;In the next post, we will look at different ways to distribute Kotlin/JS library since we've some JS exportable code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Thanks for reading! Let me know in the comments if you have questions. Also, you can reach out to me at @&lt;a href="https://twitter.com/shaktiman_droid" rel="noopener noreferrer"&gt;shaktiman_droid&lt;/a&gt; on Twitter, &lt;a href="https://www.linkedin.com/in/shaktiman-droid/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; or &lt;a href="https://slack.kotlinlang.org/" rel="noopener noreferrer"&gt;Kotlin Slack&lt;/a&gt;. And if you find all this interesting, maybe you'd like to &lt;a href="https://touchlab.co/contact-us/" rel="noopener noreferrer"&gt;work with&lt;/a&gt; or &lt;a href="https://touchlab.co/careers-3/" rel="noopener noreferrer"&gt;work at&lt;/a&gt; Touchlab.&lt;/p&gt;

</description>
      <category>kotlinjs</category>
      <category>kotlin</category>
      <category>kotlinmultiplatform</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
