contextBridge.exposeInMainWorld 和 IPC 在 Electron 应用程序中使用 Typescript:无法读取未定义的属性“发送”

2024-01-31

我定义了 contextBridge (https://www.electronjs.org/docs/all#contextbridge https://www.electronjs.org/docs/all#contextbridge) 在preload.js中如下:

const {
  contextBridge,
  ipcRenderer
} = require("electron")

contextBridge.exposeInMainWorld(
  "api", {
      send: (channel, data) => {
          ipcRenderer.invoke(channel, data).catch(e => console.log(e))
      },
      receive: (channel, func) => {
        console.log("preload-receive called. args: ");
        ipcRenderer.on(channel, (event, ...args) => func(...args));
      },
      // https://www.electronjs.org/docs/all#ipcrenderersendtowebcontentsid-channel-args
      electronIpcSendTo: (window_id: string, channel: string, ...arg: any) => {
        ipcRenderer.sendTo(window_id, channel, arg);
      },
      // https://github.com/frederiksen/angular-electron-boilerplate/blob/master/src/preload
/preload.ts
      electronIpcSend: (channel: string, ...arg: any) => {
        ipcRenderer.send(channel, arg);
      },
      electronIpcSendSync: (channel: string, ...arg: any) => {
        return ipcRenderer.sendSync(channel, arg);
      },
      electronIpcOn: (channel: string, listener: (event: any, ...arg: any) => void) => {
        ipcRenderer.on(channel, listener);
      },
      electronIpcOnce: (channel: string, listener: (event: any, ...arg: any) => void) => {
        ipcRenderer.once(channel, listener);
      },
      electronIpcRemoveListener:  (channel: string, listener: (event: any, ...arg: any) => 
void) => {
        ipcRenderer.removeListener(channel, listener);
      },
      electronIpcRemoveAllListeners: (channel: string) => {
        ipcRenderer.removeAllListeners(channel);
      }
  }
)

我定义了一个 global.ts :

export {}
declare global {
  interface Window {
    "api": {
      send: (channel: string, ...arg: any) => void;
      receive: (channel: string, func: (event: any, ...arg: any) => void) => void;
      // https://github.com/frederiksen/angular-electron-boilerplate/blob/master/src/preload
/preload.ts
      // https://www.electronjs.org/docs/all#ipcrenderersendtowebcontentsid-channel-args
      electronIpcSendTo: (window_id: string, channel: string, ...arg: any) => void;
      electronIpcSend: (channel: string, ...arg: any) => void;
      electronIpcOn: (channel: string, listener: (event: any, ...arg: any) => void) => void;
      electronIpcSendSync: (channel: string, ...arg: any) => void;
      electronIpcOnce: (channel: string, listener: (event: any, ...arg: any) => void) => 
void;
      electronIpcRemoveListener:  (channel: string, listener: (event: any, ...arg: any) =>
 void) => void;
      electronIpcRemoveAllListeners: (channel: string) => void;
    }
  }
}

在渲染器进程 App.tsx 中,我调用 window.api.send :

window.api.send('open-type-A-window', ''); 

打字稿编译看起来不错:

yarn run dev
yarn run v1.22.5 
$ yarn run tsc && rimraf dist && cross-env NODE_ENV=development webpack --watch --progress 
--color
$ tsc
95% emitting emit(node:18180) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning:      
Compilation.assets will be frozen in future, all modifications are deprecated.

BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the 
Compilation.
    Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
    Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.
(Use `node --trace-deprecation ...` to show where the warning was created)
asset main.bundle.js 32.6 KiB [emitted] (name: main) 1 related asset
asset package.json 632 bytes [emitted] [from: package.json] [copied]
cacheable modules 26.2 KiB
  modules by path ./node_modules/electron-squirrel-startup/ 18.7 KiB
    modules by path ./node_modules/electron-squirrel-startup/node_modules/debug/src/*.js 15 
KiB 4 modules
    ./node_modules/electron-squirrel-startup/index.js 1 KiB [built] [code generated]
    ./node_modules/electron-squirrel-startup/node_modules/ms/index.js 2.7 KiB [built] [code 
generated]
  ./src/main/main.ts 6.82 KiB [built] [code generated]
  ./node_modules/file-url/index.js 684 bytes [built] [code generated]
external "path" 42 bytes [built] [code generated]
external "url" 42 bytes [built] [code generated]
external "electron" 42 bytes [built] [code generated]
external "child_process" 42 bytes [built] [code generated]
external "tty" 42 bytes [built] [code generated]
external "util" 42 bytes [built] [code generated]
external "fs" 42 bytes [built] [code generated]
external "net" 42 bytes [built] [code generated]
webpack 5.21.2 compiled successfully in 4313 ms

asset renderer.bundle.js 1000 KiB [emitted] (name: main) 1 related asset
asset index.html 196 bytes [emitted]
runtime modules 937 bytes 4 modules
modules by path ./node_modules/ 990 KiB
  modules by path ./node_modules/scheduler/ 31.8 KiB 4 modules
  modules by path ./node_modules/react/ 70.6 KiB 2 modules
  modules by path ./node_modules/react-dom/ 875 KiB 2 modules
  modules by path ./node_modules/css-loader/dist/runtime/*.js 3.78 KiB 2 modules
  ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js 6.67 KiB [built] 
[code generated]
  ./node_modules/object-assign/index.js 2.06 KiB [built] [code generated]
modules by path ./src/ 5 KiB
  modules by path ./src/app/styles/*.less 3.16 KiB
    ./src/app/styles/index.less 385 bytes [built] [code generated]
    ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/app
/styles/index.less 2.78 KiB [built] [code generated]
  ./src/renderer/renderer.tsx 373 bytes [built] [code generated]
  ./src/app/components/App.tsx 1.48 KiB [built] [code generated]
webpack 5.21.2 compiled successfully in 4039 ms

但我得到Cannot read property 'send' of undefined

如果我在 App.tsx 中设置:

const sendProxy = window.api.send;

我收到同样的错误,并且窗口未呈现:

我对 Typescript 和 Electron IPC 做错了什么? 期待您的好意帮助


以下是我的设置基于https://www.electronforge.io https://www.electronforge.io,它还添加了公开的 api 的类型。希望它能有所帮助,即使不是一个有针对性的答案。

In package.json (using @ Electron-forge package.json 设置 https://www.electronforge.io/config/plugins/webpack#project-setup,webpack + typescript 模板),下entryPoints,确保您有:

"preload": {
    "js": "./src/preload.ts"
}

In src/index.ts在您创建 BrowserWindow 的位置,使用神奇的 webpack 常量来引用捆绑的预加载脚本(也许您的预加载脚本没有捆绑?):

const mainWindow = new BrowserWindow({
    webPreferences: {
      preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY
    }
  });

内容src/preload.ts:

import { contextBridge } from "electron";
import api from './api'

contextBridge.exposeInMainWorld("api", api);

src/api/index.ts只是导出 api 的所有功能。例子:

import * as myFeature from "./my-feature";

// api exports functions that make up the frontend api, ie that in
// turn either do IPC calls to main for db communication or use
// allowed nodejs features like file i/o.
// Example `my-feature.ts`: 
// export const fetchX = async (): Promise<X> => { ... }

export default {
    ...myFeature
}

Typescript 2.9+ 可以识别您的 api 函数,例如api.fetchX通过添加全局声明,例如src/index.d.ts (参考 https://stackoverflow.com/a/51114250/495244):

declare const api: typeof import("./api").default;

...您需要参考tsconfig.json:

{ 
  ...
  "files": [
    "src/index.d.ts"
  ]
}

所有这些都完成了,你应该可以打电话了api.fetchX从渲染器端提供输入支持(IDE 的 ymmv),无需导入任何内容。例子App.tsx:

import * as React from 'react'
// do not import api here, it should be globally available

export const App = () => {
  useEffect(() => {
    (async () => {
      const x = await api.fetchX();
      ...
    })();
  }, []);

  return <h1>My App</h1>
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

contextBridge.exposeInMainWorld 和 IPC 在 Electron 应用程序中使用 Typescript:无法读取未定义的属性“发送” 的相关文章

随机推荐

  • WordPress - $wpdb->插入 - MySQL NOW()

    是否有可能在 wpdb gt insert 调用中使用 MySQL NOW 当我使用以下代码时 NOW 不起作用 data array id gt NULL order gt serialize POST data Order create
  • 从另一个 .ipynb 文件导入函数

    我在名为 functions ipynb 的文件中定义了一个 hello world 函数 现在 我想使用 导入函数 导入另一个文件中的函数 我确信它们位于同一个文件夹中 但是 它仍然显示 ImportError 没有名为函数的模块 顺便说
  • fputs和fflush,写入和缓冲过程

    我对 C 中的写入处理如何进行感到困惑 所以我有一个字符串 s 我想将其写入输出 为此 我使用 fputs fputs s stdout 但显然这不会写入输出 而只是收集数据进行写入 具体是在哪里收集的 所以我必须等到程序退出或者直到我调用
  • 如何正确使用SerialPort.DiscardInBuffer?

    我编写了一个应用程序 它以非常快的速度从串行设备读取数据 然而 串行端口对象无法触发收到数据 https learn microsoft com en us dotnet api system io ports serialport dat
  • 删除单链表中的元素

    在此代码中 我删除链接列表中的元素 11 gt 12 gt 13 gt 14 gt 15 gt 12 gt 16 如果我想删除 12 它只删除第一次出现的元素 即 o p 将是 11 gt 13 gt 14 gt 15 gt 12 gt 1
  • Orgmode:如何过滤掉缠结的块?

    在 Orgmode 中 有没有办法仅缠结子树中与特定标签匹配 或不匹配 的块 例如使用以下代码 A BEGIN SRC c printf Not exported END SRC B D BEGIN SRC c printf Exporte
  • 从 Flutter 中的 Firestore 集合中获取所有内容

    我在我的项目中设置了 Firestore 我创建了名为的新集合categories 在此集合中 我创建了三个具有唯一 ID 的文档 现在我想在我的 Flutter 应用程序中获取这个集合 所以我创建了CollectionReference
  • 测试使用 Hooks 获取数据的 React 组件

    我的 React 应用程序有一个组件 可以从远程服务器获取要显示的数据 在前钩时代 componentDidMount 是该去的地方 但现在我想为此使用钩子 const App gt const state setState useStat
  • 从 PHP 数组中删除“<”和“>”标签

    我有一个像这样的数组 Array 0 gt lt email protected cdn cgi l email protection gt 1 gt lt email protected cdn cgi l email protectio
  • 创建两个日期之间所有天数的向量

    R 中是否有一种简单的方法可以列出两个指定日期之间发生的所有有效日期 例如 我想要以下输入 itemizeDates startDate 12 30 11 endDate 1 4 12 生成以下日期 12 30 11 12 31 11 1
  • 如何在rails活动记录查询中使用包含内部的联接?

    我只是想改进查询 从而提高应用程序的性能 Student includes parents gt emails where emails email address is not null and emails email address
  • VBA 用户窗体:相同字体大小的文本根据 Top 属性更改大小

    我有一个用户表单 在多个不同控件的多种情况下 我观 察到具有相同宽度 高度 字体和字体大小的对象显示不同的字体大小 具体取决于它们在用户窗体上的放置位置 上面是一个例子 这两个文本框的宽度均为 26H 和 48W Left 为 90 两者的
  • 将带有两个参数的函数应用于列

    你能用两个不同列中的值作为参数创建一个 pandas 函数吗 我有一个函数 如果两列的值在同一范围内 则返回 1 否则返回 0 def segmentMatch RealTime ResponseTime if RealTime lt 56
  • 响应正文为空,状态为 200

    我正在使用 Angular 的新 HttpClient 来处理请求 当我使用旧的 http 时 我的组件返回正文文本很好 但现在正文文本为空 我不明白 服务器正在发送它 但我总是收到 null 作为正文 响应的所有其他部分都是正常的 状态
  • UI - 如何同时显示 GridView 和 Linear 布局

    我想在网格视图下方显示 GridView 带有文本和图像 和文本框组 问题是我的 gridview 没有固定的条目 它在 1 和 10 之间变化 我想根据网格视图中的项目数量调整它的大小 我怎样才能做到这一点 在哪里可以获取JAVA代码中g
  • 如何检测 Android 中 ListView 项目的双击? [复制]

    这个问题在这里已经有答案了 我想做一些像 instagram 应用程序这样的事情 当用户在照片上双击它时 它就像 而他只按一次标签 它会以全屏方式打开 如果您不需要防止单击被触发 您可以做得更简单 Override public void
  • 类型重载宏

    我有一堆 printf 调试辅助宏 如果不指定类型 那会很酷 您可以做些什么来允许 c 中的宏重载 如果在 gcc 4 3 中可用 则可以是 gcc 特定的 我想也许是 typeof 但显然这不起作用 示例宏 我还有一些 ascii 终端颜
  • asp.net 和 .net Framework 版本是否相同?或者asp.net或clr版本是否相同?

    这是我之前的问题你好 我是网络框架的新手 你能告诉我 net框架版本和asp net版本不同吗 clr版本和asp net版本有一定关系 我如何从注册表中获取 asp net 版本 谁能给我一份版本列表 但我对这个链接感到困惑 看看瓦伦的回
  • knockoutjs:我们可以创建一个带有参数的 dependentObservable 函数吗?

    我有多个输入框 我想根据用户的选择隐藏 取消隐藏它们 我可以通过为每个输入设置一个单独的 dependentObservable 并依次使 dependentObservable 观察父级选择来实现此目的 viewModel showFie
  • contextBridge.exposeInMainWorld 和 IPC 在 Electron 应用程序中使用 Typescript:无法读取未定义的属性“发送”

    我定义了 contextBridge https www electronjs org docs all contextbridge https www electronjs org docs all contextbridge 在prel