Hey, I am trying to get environment variables into...
# javascript
h
Hey, I am trying to get environment variables into my KotlinJS application, but it just refuses to work. I use Kotlin Multiplatform with the latest gradle and kotlin version. The webpack version is v5 I think. I referenced this gist https://gist.github.com/CameronProbert/85b7d60fa9572d93566f5c5ee62441e0 and this discussion https://discuss.kotlinlang.org/t/kotlin-js-react-accessing-configuring-environment-variables/16906/6 In my webpack config I put
Copy code
;(function(config) {
    const webpack = require("webpack");
    const environmentPlugin = new webpack.DefinePlugin({
        'process.env.TEST_VALUE': JSON.stringify(process.env.TESTVALUE),
        // TEST_VALUE: process.env.TESTVALUE,
    })
    console.log("TESTVALUE: " + process.env.TESTVALUE)
    console.log(environmentPlugin)
    config.plugins.push(environmentPlugin)
})(config);
(I also tried EnvironmentPlugin but get the error TEST_VALUE undefined) In gradle I added
Copy code
webpackTask { args.plusAssign(listOf("--env", "TESTVALUE=$testVariable")) }
In my kotlin code I then get
process is not defined
and I don't know where to go from here.
I didn't know that
process
was a node library. So I added it via
implementation(devNpm("process", "0.11.10"))
And added a wrapper with
Copy code
@file:JsModule("process")
@file:JsNonModule

external val process: dynamic
I can see the process library in the node_modules in the browser, but
console.log(process)
still gives me
process is not defined
t
Do you use IR compiler?
Valid declaration for start
Copy code
external val process: dynamic
h
Yes, I do use the IR compiler
I also tried
Copy code
@file:JsModule("process/browser.js")
t
More elegant and strict:
Copy code
external object process {
    object env {
        val TEST_VALUE: String
    }
}
h
Yeah, I tried to shrink it down to avoid errors. Before I had
Copy code
external interface Process {
    val env: EnvironmentVariables
}
external object EnvironmentVariables {
    val TEST_VALUE: String
}
t
You can start from unsafe variant:
Copy code
val a = js("process.env.TEST_VALUE")
to check webpack configuration
h
I'll check again, but I also tried this I think.
t
I use compiler plugin for such declarations
You can find example example here
Configuration for
DefinePlugin
will be in generated folder
webpack.config.d
h
Oh that's a nice hint. Thank you. I tried the above and
Copy code
val test = js("process.env.TEST_VALUE")
println(test)
gives `undefined`but there is no crash.
t
You need 2 things: 1.
process.env.TEST_VALUE
call in generated JS. Without intermediate variables 2. Valid
DefinePlugin
configuration - you can find it generated sources of compiler plugin
h
seskar gives me
Configuration with name 'jsMainImplementation' not found.
My gradle JS config is
Copy code
js("jsFrontend", IR)
and
Copy code
val jsFrontendMain by getting { ... }
Okay
Copy code
const environmentPlugin = new webpack.DefinePlugin({
        'process.env.TEST_VALUE': JSON.stringify("TESTTEST"),
        // TEST_VALUE: process.env.TESTVALUE,
    })
Works, I now have to get the env into the webpack and I'm fine. Seskar also looks very good. But I'll get back to it when I have more breathing room. Thank you
Okay slight backpaddel
Copy code
val test = js("process.env.TEST_VALUE")
    println(test)
Works, but
Copy code
@file:JsModule("process")
@file:JsNonModule
package common.environment

external object process {
    object env {
        val TEST_VALUE: String
    }
}
doesn't. But that is okay for now.
t
Annotations are fully redundant
h
Oh and they actively prevented it from working. Now as a last step I need to get the variables from gradle into webpack. Thank you
Okay for the afterworld here is a working example Gradle
Copy code
val testVariable = System.getenv("TEST_VARIABLE") ?: "default"
kotlin {
    js("jsFrontend", IR) {
        binaries.executable()
        browser {
            commonWebpackConfig(
                Action {
                    // In a split multiplatform project webpack fudges the
                    // output file name, so we have to set it manually.
                    outputFileName = "${rootProject.name}-jsFrontend-js-frontend.js"
                    cssSupport {
                        enabled.set(true)
                    }
                    export = false
                }
            )
            webpackTask { args.plusAssign(listOf("--env", "TESTVALUE=$testVariable")) }
            runTask { args.plusAssign(listOf("--env", "TESTVALUE=$testVariable")) }
        }
    }
    sourceSets {
        val jsFrontendMain by getting {
            dependencies {
                implementation(devNpm("process", "0.11.10"))
            }
        }
    }
}
webpack.config.js //this snipped must be the last to be added in the resulting generated config.js
Copy code
module.exports = (env) => {
    const definePlugin = new webpack.DefinePlugin({
        'process.env.TEST_VALUE': JSON.stringify(env.TESTVALUE),
    })
    config.plugins.push(definePlugin)
    return config
}
Process.kt
Copy code
external object process {
    object env {
        val TEST_VALUE: String
    }
}
Client.kt
Copy code
val testtest = process.env.TEST_VALUE
    println(testtest)
Hope it helps.
t
plusAssign
->
+=
?
h
Tested it, also works yes