mercredi 27 décembre 2017

Kotlin To Javascript and Grails 3.3.2

Here is some sections of the build.gradle file we use for Grails 3.3.2 application, using the kotlin-gradle-plugin.

Both assemble and bootRun works fine. Assemble task generates the war file with javascript assets plugin being activated, and used after compileKotlin2Js task.

buildscript {
    ext.kotlin_version = "1.2.10"//'${kotlinVersion}'
    ext.web_dir = "grails-app/assets/javascripts/kt"
    /* . . . */
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        /* . . . */
        classpath "com.bertramlabs.plugins:asset-pipeline-gradle:2.14.7"
    }
}

/* . . . */
apply plugin: 'kotlin2js'
/* . . . */
apply plugin: "asset-pipeline"
/* . . . */

repositories {
    mavenLocal()
    jcenter()
    maven { url "http://repo.grails.org/grails/core" }
}

dependencies {
    assets "com.craigburke.angular:angular-template-asset-pipeline:2.3.0"
    assets "com.craigburke.angular:angular-annotate-asset-pipeline:2.4.0"
    /* . . . */
    runtime 'com.bertramlabs.plugins:asset-pipeline-grails:2.14.7'
    compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
}

assets {
    minifyJs = true
    minifyCss = true
    enableSourceMaps = false
    configOptions = [:] //useful for custom config on extension libraries
    minifyOptions = [
            optimizationLevel: 'SIMPLE',
            angularPass      : true
            // Can use @ngInject annotation for Angular Apps
    ]
    includes = []
    excludes = ['**/*.less'] //Example Exclude GLOB pattern
    packagePlugin = false //set to true if this is a library
    developmentRuntime = true
    jarTaskName = null
}

/* Kotlin javascript section +++ */
//sourceSets {
//    main.kotlin.srcDirs += "src/main/kotlin"
////    test.kotlin.srcDirs += "src/test/kotlin"
//}


//compileKotlin2Js {
//    kotlinOptions.outputFile = "${projectDir}/${web_dir}/MyApp.js"
//    kotlinOptions.moduleKind = "amd"
//    kotlinOptions.sourceMap = true
//}

task assembleWeb(type: Sync) {
    // Copy kotlin.js and kotlin-meta.js from jar into web directory
    configurations.compile.grep { File file ->
        file.name.startsWith("kotlin")
    }.each { File file ->
        copy {
            includeEmptyDirs = false
            def pff = zipTree(file)
            from pff
            include "*.js"
            into "${projectDir}/${web_dir}"
        }
    }
}

compileKotlin2Js.doLast() {
    copy {
        includeEmptyDirs = false
        from new File("build/classes/main")
        include "*.js"
        into "${web_dir}"
    }
}

assetCompile.dependsOn compileKotlin2Js
assetCompile.dependsOn assembleWeb
/* Kotlin javascript section --- */
/* . . . */

The important part is surrounded by "Kotlin Javascript Section" comments. 

You cannot set kotlinOptions.outputFile, because it will copy all the content of the "build/classes/main" directory into the assets directory (which is very annoying in case of Grails applications).

You have to copy "*.js" files from  "build/classes/main" directory into the assets folder you have chosen.

Usually, I would have open a bug report against this Gradle plugin for this kind of behavior, but I do not know Gradle deeply enough, and I am confused with the Intellij bug tracker system. 

Hope this helps someone!

mercredi 6 septembre 2017

Kotlin to Javascript, Gradle (Grails 3)

It is challenging to make all those happy things working together.

First, because like me, you are too lazy to read the complete Gradle stuffs, and second, because if you read Kotlinlang website, dedicated sections related to this subject, it will not work :/ .

TL; TR, here is the build.gradle file sections modified for Kotlin2Js to be alive:


buildscript {
    ext.kotlin_version = "1.1.4-3"//'${kotlinVersion}'    
    ext.web_dir = "grails-app/assets/javascripts/kt"    

[. . .]
    dependencies {

        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.grails:grails-gradle-plugin:$grailsVersion"
} [. . .] apply plugin: 'kotlin2js' [. . .] dependencies { [. . .] compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"}
    [. . .]
assets {
    [. . .] // Nothing to change
}
/* Kotlin javascript section +++ */ clean.doFirst() { delete("${web_dir}") }
build.doLast() {
        // Copy kotlin.js and kotlin-meta.js from jar into web directory    configurations.compile.each { File file ->
        configurations.compile.each { File file ->
        copy {
includeEmptyDirs = false from zipTree(file.absolutePath)
            into "${projectDir}/${web_dir}"
            include "*.js"
} } } compileKotlin2Js.doLast() { copy { includeEmptyDirs = false from new File("build/classes/main")
        include "*.js"
        into "${web_dir}"    }
        }
}
/* Kotlin javascript section --- */ bootRun { jvmArgs('-Xmx3064m', '-Dspring.output.ansi.enabled=always', '-server') } runCommand { jvmArgs('-Xmx8064m', '-Dspring.output.ansi.enabled=always', '-server') }

Assets plugin will compact the JavaScript code as expected.

If you are feed up with AngularJS, 2, 4, AngularDart ... and other Javascript FW who wants to rule the world with MVVMC and others, give Kotlin and simple DOM manipulation a chance! Everything is not perfect, but I used to enjoy static code analysis, to avoid bad behavior at runtime.

You will benefit almost simple Gradle integration (which is not yet available in Dart), IDE more efficient auto-completion, with real static analysis (AngularTS massive JSON uses, makes it more difficult).