Electron 在预加载时获取 AppData
如何获取预加载的 AppData 目录?
background.js
[...]
async function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__static, "preload.js"),
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
},
})
}
[...]
preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld(
'configManager',
require("../src/utils/config-manager")
)
config-manager.js
const app = require("electron").app
const fs = require("fs")
const resourcePath = app.getPath('appData').replaceAll("\\", "/") + "my-custom-path" // <---
const configPath = resourcePath + "config.json"
const defaultConfig = [ ... ]
let config;
function createFilesIfNotExists(){
if (!fs.existsSync(resourcePath))
fs.mkdirSync(resourcePath)
if (!fs.existsSync(configPath)){
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 4))
return true
}
return false
}
module.exports = {
loadConfig() {
createFilesIfNotExists()
[...]
return config
}
}
如果我运行它,我会收到此错误。
TypeError: Cannot read property 'getPath' of undefined
at Object.<anonymous> (VM77 config-manager.js:3)
at Object.<anonymous> (VM77 config-manager.js:65)
at Module._compile (VM43 loader.js:1078)
at Object.Module._extensions..js (VM43 loader.js:1108)
at Module.load (VM43 loader.js:935)
at Module._load (VM43 loader.js:776)
at Function.f._load (VM70 asar_bundle.js:5)
at Function.o._load (VM75 renderer_init.js:33)
at Module.require (VM43 loader.js:959)
at require (VM50 helpers.js:88)
(anonymous) @ VM75 renderer_init.js:93
我认为发生这种情况是因为“app”稍后初始化。
我的最终目标是从 AppData 目录读取 json 配置。 如果有更好的方法来做到这一点,请随时告诉我。 用户不必能够在运行时更改配置。但我必须能够将默认值从 defaultConfig
写入配置文件。
How can I get the AppData directory in preload?
background.js
[...]
async function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__static, "preload.js"),
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION
},
})
}
[...]
preload.js
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld(
'configManager',
require("../src/utils/config-manager")
)
config-manager.js
const app = require("electron").app
const fs = require("fs")
const resourcePath = app.getPath('appData').replaceAll("\\", "/") + "my-custom-path" // <---
const configPath = resourcePath + "config.json"
const defaultConfig = [ ... ]
let config;
function createFilesIfNotExists(){
if (!fs.existsSync(resourcePath))
fs.mkdirSync(resourcePath)
if (!fs.existsSync(configPath)){
fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 4))
return true
}
return false
}
module.exports = {
loadConfig() {
createFilesIfNotExists()
[...]
return config
}
}
If I run this, I get this error.
TypeError: Cannot read property 'getPath' of undefined
at Object.<anonymous> (VM77 config-manager.js:3)
at Object.<anonymous> (VM77 config-manager.js:65)
at Module._compile (VM43 loader.js:1078)
at Object.Module._extensions..js (VM43 loader.js:1108)
at Module.load (VM43 loader.js:935)
at Module._load (VM43 loader.js:776)
at Function.f._load (VM70 asar_bundle.js:5)
at Function.o._load (VM75 renderer_init.js:33)
at Module.require (VM43 loader.js:959)
at require (VM50 helpers.js:88)
(anonymous) @ VM75 renderer_init.js:93
I think this happens because "app" gets initialized later.
My final goal is to read a json config from the AppData directory.
If there is a better way to do this, feel free to tell me.
The user does not have to be able to change the config in runtime. But I must be able to write default values from the defaultConfig
into the config file.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
app.getPath()
方法仅在应用“就绪”后可用。使用app.on('ready' () => { ... });
检测 'ready' 事件。有关更多信息,请参阅 Electron 的事件:'ready' 事件。关于您的
preload.js
脚本,直接在其中包含函数有时可能会导致难以阅读和理解(即使仅通过require
实现)。目前,该文件没有关注点分离。 IE:您的“配置”功能混合在您的预加载
脚本中。如果您希望分离问题,那么您应该从preload.js
文件中重构您的“配置”代码,并将其放在自己的文件中。这样,您的preload.js
文件仅用于配置 IPC 通道和传输关联数据(如果有)。好吧,让我们看看如何解决
app.getPath('appData')
问题。在您的
main.js
文件中,检测您的应用何时“就绪”,然后通过您的config-manager.js
文件获取appData
目录。main.js
(主线程)在您的
config-manager.js
文件中,我已将您的“path”变量移至loadConfig()
函数中范围,因为它们仅由该函数使用。如果您需要将它们公开以供文件中其他位置使用,则需要将它们移回到 loadConfig() 函数范围之外。我将对
electronApp.getPath('appData')
的引用移至loadConfig()
函数中,因为这是在应用程序之后从main.js
调用的已“准备就绪”。我添加了辅助函数
pathExists()
因为它的实现被多次使用。最后,我添加了 getConfig() 函数,以便在需要时从应用程序主线程中的任何位置轻松获取配置对象(只要将其包含在需要使用它的文件中即可。IE:
let appConfig = require('config-manager')
.config-manager.js
(主线程)典型的
preload.js
脚本如下所示像这样的东西。如果您需要帮助了解 IPC 通道的实现以及如何在主线程或渲染线程中发送/接收它们,那么只需提出一个新问题。
The
app.getPath()
method is only available once the app is 'ready'. Useapp.on('ready' () => { ... });
to detect the 'ready' event. See Electron's Event: 'ready' event for more information.Regarding your
preload.js
script, having functions directly in there can make things difficult to read and understand at times (even if it is only byrequire
). Currently, there is no separation of concern with this file. IE: Your 'config' functionality is mixed inside youpreload
script. If you wish to separate concerns then you should refactor your 'config' code out of thepreload.js
file and place it in its own file. That way, yourpreload.js
file is only used for configuring IPC channels and transferring associated data if any.Ok, let's see how you would get you
app.getPath('appData')
problem solved.In your
main.js
file, detect when your app is 'ready', then through yourconfig-manager.js
file get theappData
directory.main.js
(main thread)In your
config-manager.js
file I have moved your 'path' variables into theloadConfig()
function scope as they are only use by that function. If you need them exposed for use elsewhere in your file then they will need to be moved back up out of theloadConfig()
function scope.I moved reference to
electronApp.getPath('appData')
into theloadConfig()
function as this is called frommain.js
after the app is 'ready'.I added the helper function
pathExists()
as it's implementation is used more than once.Lastly, I added the
getConfig()
function for ease of getting the config object when needed from anywhere in your app's main thread (as long as you include it in the file that needs to use it. IE:let appConfig = require('config-manager')
.config-manager.js
(main thread)Your typical
preload.js
script would look something like this.If you need help in understanding the implementation of IPC channels and how to send / receive them in either the main thread or render thread(s) then just open a new question.