Kotlin/JS, Gradle + Webpack arguments

I’m trying to use command line arguments with the gradle build task to set some behaviours in the build process. My project is React in Kotlin/JS (Legacy compiler, with some Kotlin multi-platform libraries), using build.gradle.kts, and a JS file under the webpack.config.d/ directory for adding a webpack.EnvironmentPlugin to the webpack config

Currently, I use ./gradlew browserProductionWebpack -Pmode=PROD to set Webpack’s mode to production, and also to set some Webpack Environment Plugin variables to production values, instead of prod. (https://discuss.kotlinlang.org/t/kotlin-js-react-accessing-configuring-environment-variables/16906)

This is fine if I am either developing locally (dev DB target, source maps enabled, minification disabled), or deploying to prod (prod db target, source maps disabled, minification enabled). But I want to be able to deploy to our UAT site which should be prod-like but targeting the dev DB. I also want to be able to enable or disable analytics for a build, so I can have it disabled with some run configurations, but not others.

Essentially my problem is that the only way I know how to change behaviours in the build process is through the use of the Webpack mode, which means I get only 2 options - production or development.

If I was running Webpack directly from the command line I would be able to set environment variables that I could then use to build different configurations (i.e., using Webpack’s --env command line parameter) to set the DB target separate from the build type separate from e.g. analytics enabled/disabled.

So, is there a way to use more gradle command line parameters to set build variables (the 3 I am thinking of would be -PbundleMode (for setting Webpack mode), -PenvTarget for setting the DB target and -Panalytics for enabling or disabling analytics. Or, is there an alternative way to achieve my goals?

// build.gradle.kts
import ...

val isProdBundle = project.hasProperty("bundleMode") && (project.property("bundleMode") as String).toUpperCase() == "PROD"
val isProdEnv = project.hasProperty("envTarget") && (project.property("envTarget") as String).toUpperCase() == "PROD"
val isAnalyticsEnabled = project.hasProperty("analytics") && (project.property("analytics") as String).toUpperCase() == "true"

buildscript {
    ...
}

plugins {
    ...
}

repositories {
    ...
}

kotlin {
    js {
        browser {
            commonWebpackConfig {
                cssSupport.enabled = true
                mode = if (isProdBundle) PRODUCTION else DEVELOPMENT
            }

            // I tried using this to add env variables to the webpack config task
            // webpackTask {
            //    this.args.addAll(listOf(
            //         "--env ENV_TARGETS=${if (isProdEnv) "prod" else "dev"}",
            //        "--env production=$isProdBundle",
            //        "--env ENABLE_ANALYTICS=$isAnalyticsEnabled"
            //    ))
            //}
        }
        ...
    }
    ...
}

dependencies {
    ...
}

And JS config file file:

// webpack.config.d/firebaseConfig.js
const webpack = require("webpack")

var apiKey;
var projectId;
var appId;
var authDomain;
var databaseUrl;
var storageBucket;
var messagingSenderId;
var measurementId;
var locationApiKey;
var gtmId;

if (config.mode.toLowerCase() === "production") { // the build process makes the config object available
  apiKey = ... // Set all above variables to prod values
} else {
  apiKey = ... // Set all above variables to dev values
}

const environmentPlugin = new webpack.EnvironmentPlugin(
  {
	FIREBASE_API_KEY: apiKey,
	FIREBASE_PROJECT_ID: projectId,
	FIREBASE_APP_ID: appId,
	FIREBASE_AUTH_DOMAIN: authDomain,
	FIREBASE_DATABASE_URL: databaseUrl,
	FIREBASE_STORAGE_BUCKET: storageBucket,
	FIREBASE_MESSAGING_SENDER_ID: messagingSenderId,
	FIREBASE_MEASUREMENT_ID: measurementId,
	LOCATION_API_KEY: locationApiKey,
	GTM_ID: gtmId,
  }
)

config.plugins.push(environmentPlugin)

Thanks,
Cam

I seem to have this working using @simonjacobs answer here: https://discuss.kotlinlang.org/t/kotlin-js-react-accessing-configuring-environment-variables/16906/9

Can you post your updated code that is working?
Edit: I am struggling with the exact same issue and have the exact same usecase, so @CameronProbert please be my saviour

Additional question, with this setup, how do you securely store firebase credentials? As it seems you hardcode them in the webpack config? Isn’t this a safety concern?

Hi, I made this gist here. Hopefully that is everything you need!

As for your other question, as far as I understand it you can’t really get around that when using Firebase for the web. Because it is all client side the credentials must be available on the client. This should not be an issue though, because you should use Firebase’s security rules to secure all your data on the server.

1 Like

@CameronProbert Thank you so much for taking the time to write up such a detailed response! :pray:t2: