即使在 webpack.DefinePlugin 中设置了环境变量,也没有在电子中定义

2022-01-10 00:00:00 reactjs node.js electron javascript webpack

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

I have a requirement where we need to set dll path based upon whether it is executing in production or in development environment. So I decided to place that value in environment variable and tried to achieve that using webpack.DefinePlugin({}).

方法一:

webpack.config.json

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

然后我尝试在电子的主进程中获取该值,在我的例子中是 elec.js

And then I tried to get that value in electron's main process, In my case 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() 函数中访问该值时,它是未定义的,因此流程总是转到 else 块.

But problem is that when I try to access that value in createWindow() function it is undefined so flow always goes to else block.

我有什么遗漏吗?

方法二:

我尝试使用跨环境节点包来实现相同的目标,但没有运气.请在下面找到我尝试使用 cross-env 的代码块.

I tried to achieve the same using cross-env node package, but no luck. Please find below code block which I tried using 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/"
    }

推荐答案

iva2k 提供的洞察力使我能够为同样的问题找到解决方案.

The insight provided by iva2k is what allowed me to come to a solution for this same problem.

使用 dotenv 为我的配置创建一个 .env 文件我到了我想去的地方的一半(设置一些环境变量以在生产环境中使用).然后问题就变成了 Electron 默认没有将那些从 Main 进程传递到 Renderer 进程.

Using dotenv to create a .env file for my config got me halfway to where I wanted to be (setting up a few environment variables for use in a production setting). The problem then became that Electron wasn't passing those from the Main process down to the Renderer process by default.

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

The work-around is simple: use Electron's own ipcMain and ipcRenderer modules to pass the dotenv object between the two.

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

In your main file (e.g. your elec.js file), place an ipcMain event listener after requiring the module:

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);
});

在应用程序的渲染端,将其放置在任何需要的地方:

Elsewhere, in your application's rendering-side, place this anywhere necessary:

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;
}

这基本上允许我在主进程文件中声明一个事件,然后在我想要的任何进程端文件中重新使用它,从而允许我在与构建一起的文件中混淆配置变量,但不是如果不打开开发工具,最终用户将无法访问.

This basically allowed me to declare one event in the Main process file, and then re-use it in any process-side file I wanted, thus allowing me to obfuscate config variables in a file that goes with the build, but isn't accessible to end-users without opening up the dev-tools.

相关文章