I’m curious how I would use .env, .env.local, etc. in my Kotlin React application. I am using gradle, and essentially I want to be able to use different values depending upon my environment. Typically I would just create my .env and access process.env.VAR_NAME and I’m good. So, I thought I would try using something like “external val process: dynamic” and then accessing my variables like so. However, it doesn’t seem to work, possibly because the .env doesn’t get picked up? Anyone solve this?
Thanks for any feedback advice. Also, on a curious note, how would one suggest using ‘create-react-kotlin-app’ in an automated build process? That’s the main reason I choose gradle. I am open to ideas and suggestions.
How would you expect this to work? When the JavaScript is being executed in a browser there are no environment variables like there would be in a NodeJS or JVM process. You’d need to find a way to make the values accessible in variables in the browser.
I’m doing this using Webpack’s DefinePlugin and different configuration files which are loaded in the Webpack configuration depending on whether the build is in development or production mode. Not exactly elegant but does the job.
You can execute extra code on your webpack configuration by placing JS files in a webpack.config.d directory (docs). You can put, for example:
//webpack.config.d/additional-config.js
const webpack = require("webpack")
var one, two
if (config.mode === "production") { // the build process makes the config object available
one = "production_one"
two = "production_two"
}
else {
one = "development_one"
two = "development_two"
}
const definePlugin = new webpack.DefinePlugin(
{
ENV_VAR_ONE: one,
ENV_VAR_TWO: two
}
)
config.plugins.push(definePlugin)
Then back in Kotlin, if you put something like:
// inside Kotlin class
val environmentVariableOne = js("ENV_VAR_ONE")
val environmentVariableTwo = js("ENV_VAR_TWO")
then you should magically find that the variables are set to the values from the config file depending on the mode. The mode can be set in Gradle:
// build.gradle.kts
kotlin { // This is the JS plugin setup. There's an extra js closure for Multiplatform
target {
browser {
webpackTask {
mode = if (condition) Mode.DEVELOPMENT else Mode.PRODUCTION
}
}
}
}
So then you have a way to transport variables defined during the build to the code depending on environment type.
one issue that we are having is that we can’t test minified builds on the development environment with this solution. Also, we can’t have more than 2 environments (e.g., test, dev, prod).
After a bit more thinking, I see you can pass arbitrary values to the Webpack configuration (and so your Kotlin program in turn if desired) from the Gradle build using the Webpack environment variables feature (Webpack v4 docs – note the Kotlin plugin currently uses this version). To do this you also need to adjust the Webpack configuration file so that it exports a function. To illustrate:
This appears to work for me. If anyone else is stuck, one thing that I spent a long time debugging was why this didn’t seem to work for my run configuration using ./gradlew run (or ./gradlew browserDevelopmentRun). The ‘webpack’ in webpackTask specifically refers to ./gradlew browserDevelopmentWebpack or ./gradlew browserProductionWebpack tasks, so if you want this to run with browserDevelopmentRun you need to add a runTask {...} section under browser also.
Create an .env file and place it at the root of your project folder:
//.env
MY_ENV_VAR=some_value
In our webpack configuration file, save the environment variables to a property name of your choice (mine was PROCESS_ENV):
// webpack.config.d/config.js
var webpack = require("webpack");
var path = require('path');
var dotenv = require('dotenv').config({ path: path.resolve(__dirname, '../../../../.env') });
var definePlugin = new webpack.DefinePlugin(
{
"PROCESS_ENV": JSON.stringify(dotenv.parsed)
}
)
config.plugins.push(definePlugin)
In Kotlin kode, you can access whichever process env variables you need:
// ExampleFile.kt
val processEnv = js("PROCESS_ENV")
val someValue = processEnv.MY_ENV_VAR // some_value
The above works well when building the app locally. In my experience, deploying to a service like Heroku/Netlify/Vercel, you’ll need to edit the config.js file to export the process.env object to WebPack without dotenv:
// webpack.config.d/config.js
var webpack = require("webpack");
var definePlugin = new webpack.DefinePlugin(
{
"PROCESS_ENV": JSON.stringify(process.env)
}
)
config.plugins.push(definePlugin)