9

I'm building an Electron, React app where I'm in need of a dotenv file. In code, I call my variables with process.env.variable which works fine in development.

However, once distributed with electron-builder, the dotenv variables no longer work (undefined).

My question is now, is it even possible to do this and if yes, how? I tried to find a solution in the internet but it seems like people don't really face this issue.

Scorpia
  • 375
  • 4
  • 15

1 Answers1

0

Not sure if this question is still valid, but here is what I got in case anyone has the same question. If you are using electron-builder, this is not supported natively at the moment.

ENVS don't load in the distributable, as electron-builder is a packager, not a bundler. ENVs only load for configuring the packaging step. (From eletron-builder collaborator)

https://github.com/electron-userland/electron-builder/issues/7143

But that does not mean there aren't any other way around, here is my dirty way of work around on this, I created a script to replace the env placeholder used for electron-builder build --publish.

I'm using React boilerplate, it might be different on yours respected framework. So I create a script to replace env in the app/dist/main/main.js when the webpack finished transpiling my TS to JS files, it should be right before the eletron-builder bash line got executed.

Here is a detailed of what I did:

Folder structure

app
    scripts(self-created)
          packageEnv.js
    ...

package.json:

"scripts": {
    "build": "concurrently \"npm run build:main\" \"npm run build:renderer\"",
    "package:env": "node ./scripts/packageEnv.js",
    "build:main": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.main.prod.ts",
    "build:renderer": "cross-env NODE_ENV=production TS_NODE_TRANSPILE_ONLY=true webpack --config ./.erb/configs/webpack.config.renderer.prod.ts",
    "package": "ts-node ./.erb/scripts/clean.js dist && npm run build && npm run package:env && electron-builder build --publish never",
    "rebuild": "electron-rebuild --parallel --types prod,dev,optional --module-dir release/app",
  },

Code for packageEnv.js (it's super dirty, I would recommend to read and refactor it). Placed some TODO there as well.

const fs = require('fs');

const splitLineIntoPairs = (line) => {
  const firstEqualSymbolPosition = line.search('=');
  const key = line.slice(0, firstEqualSymbolPosition).replaceAll(' ', '');
  const values = line
    .slice(firstEqualSymbolPosition + 1, line.length)
    .replaceAll(' ', '');
  return {
    key,
    values,
  };
};

const createEnvObj = (envByLines) => {
  return envByLines.map((line) => {
    const { key, values } = splitLineIntoPairs(line);
    return {
      key,
      values,
    };
  });
};

const writeEnvToDistApp = ({ path, env }) => {
  // TODO: Should make it so that the code read by chunks instead of loading entire file, may encounter memory shortage if file too big atm
  let mainJs = fs.readFileSync(path).toString();
  env.forEach(({ key, values }) => {
    // TODO: Replace with your env variable template
    mainJs = mainJs.replace(`process.env.${key}`, `"${values}"`);
  });
  fs.writeFileSync(path, mainJs);
};

const packageEnv = () => {
  const envFileContent = fs.readFileSync('./.env').toString();
  const envByLines = envFileContent.split('\n').filter((line) => {
    return line !== '';
  });
  const envObj = createEnvObj(envByLines);
  writeEnvToDistApp({
    // TODO: Replace with your release app structure
    path: './release/app/dist/main/main.js',
    env: envObj,
  });
};

packageEnv();
Vũ Thành Tâm
  • 442
  • 2
  • 8