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

Posted

技术标签:

【中文标题】即使在 webpack.DefinePlugin 中设置了环境变量,也没有在电子中定义【英文标题】:Environment variable is undefined in electron even it has been set inside webpack.DefinePlugin 【发布时间】:2018-07-17 14:18:19 【问题描述】:

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

方法一:

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() 函数中访问该值时,它是未定义的,因此流程总是转到 else 块。

我有什么遗漏吗?

方法二:

我尝试使用跨环境节点包来实现相同的目标,但没有运气。请在下面找到我尝试使用 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/"
    

【问题讨论】:

【参考方案1】:

在您的控制台中

对于 Windows 设置 MY_VARIABLE=true

对于 Linux $ export MY_VARIABLE=true

window.process.env.MY_VARIABLE

【讨论】:

【参考方案2】:

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;

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

【讨论】:

【参考方案3】:

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

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

【讨论】:

【参考方案4】:

问题是多方面的。

首先,您的 elec.js 在应用加载之前由 Electron 执行。 Electron 运行 elec.js,它创建浏览器窗口 (let win = new BrowserWindow(...)) 并将 HTML 文件 (win.loadURL(...)) 加载到浏览器进程中,然后 HTML 加载您的 webpack 的 js。所以在 elec.js 中没有任何 webpacked js 代码可用。 webpack 的代码也在 elec.js 之外的另一个进程中运行。

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

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

因此,所有这些都使得构建/webpack 时间的 process.env.NODE_ENV 在 elec.js 代码中不可用。

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

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

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

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

    根据构建在 package.json 中使用不同的版本(例如,版本:“1.0.0-DEBUG”用于调试),并通过调用 elec.js 中的 app.getVersion() 来读取和解析它。这很棘手,因为 package.json 应该是单个文件,但可以使用操作系统命令(例如在“脚本”中)在调用 npm 之前复制准备好的 package.json 文件之一。

这里有一些链接也可以提供帮助:

Electron issue #7714 - Electron 相关特性的讨论

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

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

【讨论】:

以上是关于即使在 webpack.DefinePlugin 中设置了环境变量,也没有在电子中定义的主要内容,如果未能解决你的问题,请参考以下文章

我在 webpack.DefinePlugin 中定义的变量未定义

使用来自 WebPack.DefinePlugin 的全局注入变量进行 NodeJS Mocha 单元测试

什么是用于 create-react-app 的 webpack.DefinePlugin 的良好替代品?

通过外部文件中的webpack.DefinePlugin设置变量 - 异步读取问题

webpack

在webpack中区分环境变量