electron / packager

Customize and package your Electron app with OS-specific bundles (.app, .exe, etc.) via JS or CLI
https://npm.im/@electron/packager
BSD 2-Clause "Simplified" License
175 stars 17 forks source link

Package with process.env variables set #259

Closed mmahalwy closed 8 years ago

mmahalwy commented 8 years ago

In my main.js file, I have process.env variables set that I need to package and have them set when you open the packaged app. How can I do this? Here is my package.js file:

/* eslint strict: 0, no-shadow: 0, no-unused-vars: 0, no-console: 0 */
'use strict';

const os = require('os');
const webpack = require('webpack');
const cfg = require('./webpack/app.production.js');
const packager = require('electron-packager');
const del = require('del');
const exec = require('child_process').exec;
const argv = require('minimist')(process.argv.slice(2));
const pkg = require('./package.json');
const devDeps = Object.keys(pkg.devDependencies);

const appName = argv.name || argv.n || pkg.productName;
const shouldUseAsar = argv.asar || argv.a || false;
const shouldBuildAll = argv.all || false;

console.log(process.env.GOOGLE_APP_CLIENT);

const DEFAULT_OPTS = {
  dir: './',
  name: appName,
  asar: shouldUseAsar,
  ignore: [
    '/test($|/)',
    '/tools($|/)',
    '/release($|/)'
  ].concat(devDeps.map(name => `/node_modules/${name}($|/)`))
};

const icon = argv.icon || argv.i || 'app/app';

if (icon) {
  DEFAULT_OPTS.icon = icon;
}

const version = argv.version || argv.v;

if (version) {
  DEFAULT_OPTS.version = version;
  startPack();
} else {
  // use the same version as the currently-installed electron-prebuilt
  exec('npm list electron-prebuilt', (err, stdout) => {
    if (err) {
      DEFAULT_OPTS.version = '0.36.2';
    } else {
      DEFAULT_OPTS.version = stdout.split('electron-prebuilt@')[1].replace(/\s/g, '');
    }

    startPack();
  });
}

function startPack() {
  console.log('start pack...');
  webpack(cfg, (err, stats) => {
    if (err) return console.error(err);
    del('release')
    .then(paths => {
      if (shouldBuildAll) {
        // build for all platforms
        const archs = ['ia32', 'x64'];
        const platforms = ['linux', 'win32', 'darwin'];

        platforms.forEach(plat => {
          archs.forEach(arch => {
            pack(plat, arch, log(plat, arch));
          });
        });
      } else {
        // build for current platform only
        pack(os.platform(), os.arch(), log(os.platform(), os.arch()));
      }
    })
    .catch(err => {
      console.error(err);
    });
  });
}

function pack(plat, arch, cb) {
  // there is no darwin ia32 electron
  if (plat === 'darwin' && arch === 'ia32') return;

  const iconObj = {
    icon: DEFAULT_OPTS.icon + (() => {
      let extension = '.png';
      if (plat === 'darwin') {
        extension = '.icns';
      } else if (plat === 'win32') {
        extension = '.ico';
      }
      return extension;
    })()
  };

  const opts = Object.assign({}, DEFAULT_OPTS, iconObj, {
    platform: plat,
    arch,
    prune: true,
    out: `release/${plat}-${arch}`
  });

  packager(opts, cb);
}

function log(plat, arch) {
  return (err, filepath) => {
    if (err) return console.error(err);
    console.log(`${plat}-${arch} finished!`);
  };
}
malept commented 8 years ago

Just so I'm clear, the person who packages the app sets an environment variable, and then every person who installs it runs the app with that environment variable set to the exact value that the packager set?

mmahalwy commented 8 years ago

@malept correct! The whole is for the packager to set env variables that will be consistent amongst all downloaded versions. This is used for setting variables like Google client keys, etc. If you have better solutions, I am certainly open to setting secret api keys, etc. in the app. I'd prefer that over process envs

malept commented 8 years ago

Does it have to be an environment variable?

mmahalwy commented 8 years ago

@malept sorry, what do you mean by will get picked up by electron-packager?

malept commented 8 years ago

For example, in the same location as your main.js. Somewhere where you can call require.

mmahalwy commented 8 years ago

@malept i am having some trouble with this actually in doing it in an elegant way. There is no way to tell Electron what env it is on after packaged and on opening the application such that it uses some env variables and not others. My only solution is creating and deleting files on packaging or developing which is not elegant in any way.

malept commented 8 years ago

Given an app that looks like this:

main.js
package.json

And a package.json that looks like this:

{
  "name": "MyApp",
  "main": "main.js",
  "devDependencies": {
    "electron-packager": "^5.2.1",
    "electon-prebuilt": "^0.36.0"
  }
}

I would have a main.js that starts like this:

require('frozenenv');

...and a shell script build.sh:

#!/bin/bash

npm install
echo "process.env.FOOBAR = '$FOOBAR';" > frozenenv.js
electron-packager . --out ../packages --all

What it amounts to is a different way of creating a config file. I am not aware of any other method of configuring a packaged app that involves "freezing" environment variables that doesn't look something like this.

mmahalwy commented 8 years ago

@malept i ended up using jsonfile to write json then erase it later.