2

I am using electron-builder to package a React app. My app uses the create-react-app boilerplate.

Is there a way I can set a variable at compile time, so that it can be used in a conditional within the code in the main process at runtime...?

I'm looking for an equivalent to C's preprocessor macros. So I could do something like:

electron-builder --extraConfig BUILD_TYPE=testing

Then in my main.js:

if (extraConfig.BUILD_TYPE === 'testing') { // do stuff }

j b
  • 5,147
  • 5
  • 41
  • 60

2 Answers2

0

I've done this before but I'm using electron-webpack in addition to what you already have:

electron ^11.2.0
electron-builder ^22.9.1
electron-webpack ^2.8.2
webpack ^4

The idea is to expose a variable via webpack.DefinePlugin and you can do this for both your main and renderer processes.

With electron-webpack you can provide a webpack configuration for both processes:

// webpack.main.config.js
const webpack = require('webpack');
module.exports = {
  plugins: [ new webpack.DefinePlugin({__BURRITO__: true}) ]
};

// webpack.renderer.config.js
const webpack = require('webpack');
module.exports = {
  plugins: [ new webpack.DefinePlugin({__TACO__: true}) ]
};

These two files are exposed to electron-webpack via a bit of configuration in package.json:

{
  …
  "electronWebpack": {
    "main": {
      "webpackConfig": "webpack.main.config.js"
    },
    "renderer": {
      "webpackConfig": "webpack.renderer.config.js"
    }
  }
}

Then in your main process:

// src/main/index.js
const {app, BrowserWindow} = require('electron')

app.whenReady().then(() => {
  const mainWindow = new BrowserWindow({webPreferences: {nodeIntegration: true}});
  console.log(__BURRITO__ ? "" : "");
  mainWindow.loadURL(`http://localhost:${process.env.ELECTRON_WEBPACK_WDS_PORT}`);
});

Two things:

  1. The .loadURL bit looks funny but that's only because I'm using electron-webpack default html template for the renderer. During development it is served through this local server.

  2. You shouldn't need to enable the nodeIntegration flag. That is only because electron-webpack default renderer template uses a few require statements here and there.

If your renderer process includes some scripts they'll have access to your at-compile-time variable too. Here again I'm leveraging electron-webpack default template which requires src/renderer/index.js automatically:

// src/renderer/index.js
if (__TACO__) {
  document.body.innerHTML = ""
}

When you run this via electron-webpack dev then you can see two things:

  1. A burrito is seen in the output of the main process
  2. A taco is seen in the html of the renderer process

This shows that electron-webpack successfully injected two variables at compile time.

enter image description here

customcommander
  • 17,580
  • 5
  • 58
  • 84
  • thanks! Are you using create-react-app...? If I follow the instructions above, I get an error `Support for the experimental syntax 'jsx' isn't currently enabled` then `Add @babel/preset-react (https://git.io/JfeDR) to the 'presets' section of your Babel config to enable transformation`. Any ideas? – j b Jan 28 '21 at 14:39
  • I'm not but I'm definitely using React and Babel in the project I'm working on that uses that approach and it works fine. Setting Babel & React can be a long and frustrating journey though! – customcommander Jan 28 '21 at 14:52
0

I'd put the electron-builder command in an NPM script, then run another script beforehand to set BUILD_TYPE in a .txt file.

Like this:

package.json:

"scripts": {
    "distProd": "node ./setBuildType.js prod && electron-builder",
    "distDev": "node ./setBuildType.js dev && electron-builder",
}

Then inside setBuildType.js:

// process.argv[2] Contains the type.
fs.writeFile('./BUILD_TYPE.txt', process.argv[2], function (errObj) {
    if (errObj) {
        console.log(errObj);
    }
});

Then from your app, get BUILD_TYPE with:

// Always set `BUILD_TYPE` to `dev` when running from the terminal.
if (!app.isPackaged) {
    var BUILD_TYPE = fs.readFileSync('./BUILD_TYPE.txt');
} else {
    var BUILD_TYPE = 'dev';
}
console.log(BUILD_TYPE); // Outputs "prod" or "dev".

That'll check if it's running from an installer or from the terminal, if it's running from the terminal then it'll always set BUILD_TYPE to dev.

Joshua
  • 5,032
  • 2
  • 29
  • 45