环境变量在电子中未定义,即使它已在webpack.DefinePlugin中设置

时间:2018-02-07 10:22:37

标签: javascript node.js reactjs webpack electron

我有一个要求,我们需要根据它是在生产环境还是在开发环境中执行来设置dll路径。所以我决定将该值放在环境变量中并尝试使用webpack.DefinePlugin({})来实现它。

方法1:

webpack.config.json

plugins: [
new webpack.DefinePlugin({
    'process.env.NODE_ENV' : JSON.stringify('production')
})

然后我试图在电子的主要过程中获得这个价值,在我的案例中是elec.js

elec.js

const Electron = require("electron");
const app = require("electron");

var dllPath = "";

function createWindow() {
  let win = new BrowserWindow({
    width: 800,
    height: 600,
    title: "Test",
    icon: "Test.ico"
  });

  win.setMenu(null);

  win.loadURL(
    url.format({
      pathname: path.join(__dirname, "../renderer/index.html"),
      protocol: "file:",
      slashes: true
    })
  );

if (process.env.NODE_ENV ==='production') {
    dllPath = path.join(
      __dirname,
      "./../../dll/test.dll"
    );
  } else {
    dllPath = path.join(
      __dirname,
      "./../../../dll/test.dll"
    );
  }
}

app.on("ready", createWindow);

但问题是当我尝试在createWindow()函数中访问该值时,它是未定义的,所以flow总是转到else块。

我有什么遗失的吗?

方法2:

我尝试使用cross-env节点包实现相同,但没有运气。请在下面的代码块中找到我尝试使用cross-env。

package.json

 "scripts": {
          "build": "cross-env process.env.NODE_ENV=production && rimraf ./dist/ && webpack --progress && node-sass 
           ./src/renderer/scss/ -o ./dist/renderer/ && rimraf ./dist/renderer/includes/"
    }

4 个答案:

答案 0 :(得分:0)

问题是多方面的。

首先,在加载应用之前,您的 elec.js 由Electron执行。 Electron运行elec.js,它创建浏览器窗口(let win = new BrowserWindow(...))并在浏览器进程中加载​​HTML文件(win.loadURL(...)),然后HTML加载你的webpack' ed js。因此,elec.js中没有任何webpacked js代码。 webpack的代码也在elec.js以外的其他进程中运行。

需要注意的另一件事是webpack插件不会为它指向的变量创建任何赋值。它通过简单的文本搜索和替换完成,在您的示例中,process.env.NODE_ENV的所有实例将替换为" production"源代码中的字符串是webpack' ed。这不是太明显,但会弄乱预期的结果。

最后一件事 - webpack插件不会更改elec.js文件中的任何代码,因为该文件不是webpack'

所以这一切使得build / webpack时间的process.env.NODE_ENV在elec.js代码中不可用。

一旦机制明确,解决问题的方法很少,我会给出一般性的想法,因为每个都有很多讨论,根据情况和期望的用例,有些比其他更好:

  1. 在构建期间根据环境变量生成具有必要赋值的js文件(例如,复制env-prod.js / env-dev.js - > env.js中的一个),将其复制到elec旁边。 js,并在elec.js中引用它(require(env.js)

  2. 从命令行传递环境变量(例如NODE_ENV=1 electron .) - 它将转到elec.js。

  3. 根据环境变量将文件包含到webpack中(例如复制env-prod.js / env-dev.js - > env.js中的一个)并查看webpacked'来自elec.js的文件,例如使用asar命令。

  4. 根据构建情况在package.json中使用不同的版本(例如版本:" 1.0.0-DEBUG"用于调试),并阅读&通过在elec.js中调用app.getVersion()来解析它。这很棘手,因为package.json应该是一个单独的文件,但是可以使用OS命令(例如在"脚本"中)来复制一个准备好的package.json文件,然后再调用npm。

  5. 以下是一些可能有用的链接:

    Electron issue #7714 - 关于Electron相关功能的讨论

    electron-is-dev - 模块检查它是否在dev

    Electron boilerplate - 使用config / env-prod / dev文件的示例样板

答案 1 :(得分:0)

也许晚了,但是可以在elec.js中使用简单的技巧

const isProduction = process.env.NODE_ENV === 'production' || (!process || !process.env || !process.env.NODE_ENV);

答案 2 :(得分:0)

iva2k提供的见解使我得以解决同一问题。

使用dotenv为我的配置创建一个.env文件使我到了想要的位置(设置了一些环境变量以用于生产环境)。问题是,Electron默认不会将它们从 Main 进程传递到 Renderer 进程。

解决方法很简单:使用Electron自己的ipcMainipcRenderer模块在​​两者之间传递dotenv对象。

在您的主文件(例如您的 elec.js 文件)中,在需要模块之后放置一个ipcMain事件监听器:

const config = require('dotenv').config();
const electron = require('electron');
const { app, BrowserWindow, ipcMain } = electron;

...

ipcMain.on('get-env', (event) => {
    event.sender.send('get-env-reply', config);
});

在其他地方,在应用程序的呈现端,将其放置在必要的位置:

async function getConfig() 
{
    const { ipcRenderer } = window.require('electron');
    let config = null;
    ipcRenderer.on('get-env-reply', (event, arg) => {
        // The dotenv config object should return an object with
        // another object inside caled "parsed". Change this if need be.
        config = arg.parsed;
    });
    ipcRenderer.send('get-env');

    return config;
}

这基本上使我可以在Main进程文件中声明一个事件,然后在所需的任何进程端文件中重复使用它,从而使我能够混淆与构建一起提供的文件中的配置变量,但不能如果不打开开发工具,最终用户将无法访问。

答案 3 :(得分:0)

在您的控制台中

对于Windows 设置MY_VARIABLE = true

对于Linux $ export MY_VARIABLE = true

window.process.env.MY_VARIABLE