Bundle Kotlin/JS project in single file for NodeJS execution

I managed with a custom tasks to generate the configuration:

open class GenerateWebpackConfig : DefaultTask() {

    enum class Target {
        NODE, BROWSER
    }

    private val template = """
        module.exports = [{
            name: 'server',
            entry: '%%%ENTRY%%%',
            target: '%%%MODE%%%', // <-- importat part!
            output: {
                path: '%%%OUTPUT_PATH%%%',
                filename: '%%%OUTPUT_NAME%%%',
            },
            resolve: {
                modules: [%%%MODULES_FOLDER%%%]
            }
        }];
    """.trimIndent()

    @get:InputFile
    var entryFile by project.objects.property<File>()

    @get:Input
    var target: Target = Target.NODE

    @get:Input
    var outputBundleFolder by project.objects.property<String>()

    @get:Input
    var outputBundleName by project.objects.property<String>()

    @get:InputFiles
    var modulesFolder = project.objects.listProperty(File::class)

    @get:OutputFile
    var outputConfig by project.objects.property<File>()

    init {
        with(project) {
            outputBundleFolder = file("$buildDir\\bundle").absolutePath
            outputBundleName = "bundle.js"
            modulesFolder.set(listOf(file("node_modules")))
            outputConfig = file("$buildDir/config/webpack.config.js")
        }
    }

    @TaskAction
    fun buildFile() {
        outputConfig.writeText(
            template.replace("%%%ENTRY%%%", entryFile.absolutePath.replace("\\", "\\\\"))
                .replace("%%%MODE%%%", target.toString().toLowerCase())
                .replace("%%%OUTPUT_PATH%%%", outputBundleFolder.replace("\\", "\\\\"))
                .replace("%%%OUTPUT_NAME%%%", outputBundleName)
                .replace(
                    "%%%MODULES_FOLDER%%%",
                    modulesFolder.get().joinToString(",") { "'${it.absolutePath.replace("\\", "\\\\")}'" }
                )
        )
    }
}

And the buildscript:

import com.github.gradle.node.task.NodeTask
import it.belabs.gradle.tasks.GenerateWebpackConfig
import it.belabs.gradle.tasks.GenerateWebpackConfig.Target.NODE
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.KotlinPackageJsonTask
import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile

plugins {
    kotlin("js")
    id("com.github.node-gradle.node")
}

kotlin {
    js {
        useCommonJs()
        nodejs()
        binaries.executable()
    }
}

val compileKotlinJs by tasks.getting(Kotlin2JsCompile::class)
val packageJson by tasks.getting(KotlinPackageJsonTask::class)
val rootPackageJson by rootProject.tasks.getting(RootPackageJsonTask::class)

val generateWebpackConfig by tasks.creating(GenerateWebpackConfig::class) {
    target = NODE
    entryFile = compileKotlinJs.outputFile
    modulesFolder.set(listOf(File(rootPackageJson.rootPackageJson.parentFile, "node_modules")))
}

val packAction by tasks.creating(NodeTask::class) {
    group = "distribution"
    dependsOn(generateWebpackConfig, compileKotlinJs, rootPackageJson, tasks.npmInstall)
    script.set(file("node_modules/webpack-cli/bin/cli.js"))
    args.set(listOf("-c", generateWebpackConfig.outputConfig.absolutePath))
}

the tasks that generated the configurations are compileKotlinJs, packageJson and the rootProject task rootPackageJson. I was able to install webpack and webpack-cli locally with a local package.json using the Node Gradle Plugin and invoking it via a task. Gosh the JS tooling ecosystem is messed up!

3 Likes