mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-23 13:29:02 +08:00
feat: init window.affine (#2682)
(cherry picked from commit 8f6db00402)
This commit is contained in:
@@ -1,5 +1,3 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
// NOTE: we will generate preload types from this file
|
// NOTE: we will generate preload types from this file
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { contextBridge, ipcRenderer } from 'electron';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const affineApis = await import('./affine-apis');
|
||||||
|
contextBridge.exposeInMainWorld('apis', affineApis.apis);
|
||||||
|
contextBridge.exposeInMainWorld('events', affineApis.events);
|
||||||
|
contextBridge.exposeInMainWorld('appInfo', affineApis.appInfo);
|
||||||
|
|
||||||
|
// Credit to microsoft/vscode
|
||||||
|
function validateIPC(channel: string) {
|
||||||
|
if (!channel || !channel.startsWith('affine:')) {
|
||||||
|
throw new Error(`Unsupported event IPC channel '${channel}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const globals = {
|
||||||
|
ipcRenderer: {
|
||||||
|
send(channel: string, ...args: any[]) {
|
||||||
|
if (validateIPC(channel)) {
|
||||||
|
ipcRenderer.send(channel, ...args);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
invoke(channel: string, ...args: any[]) {
|
||||||
|
if (validateIPC(channel)) {
|
||||||
|
return ipcRenderer.invoke(channel, ...args);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
on(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void
|
||||||
|
) {
|
||||||
|
if (validateIPC(channel)) {
|
||||||
|
ipcRenderer.on(channel, listener);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
once(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void
|
||||||
|
) {
|
||||||
|
if (validateIPC(channel)) {
|
||||||
|
ipcRenderer.once(channel, listener);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
removeListener(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void
|
||||||
|
) {
|
||||||
|
if (validateIPC(channel)) {
|
||||||
|
ipcRenderer.removeListener(channel, listener);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
contextBridge.exposeInMainWorld('affine', globals);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
@@ -1,18 +1 @@
|
|||||||
/**
|
import './bootstrap';
|
||||||
* @module preload
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { contextBridge } from 'electron';
|
|
||||||
|
|
||||||
import * as affineApis from './affine-apis';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The "Main World" is the JavaScript context that your main renderer code runs in.
|
|
||||||
* By default, the page you load in your renderer executes code in this world.
|
|
||||||
*
|
|
||||||
* @see https://www.electronjs.org/docs/api/context-bridge
|
|
||||||
*/
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('apis', affineApis.apis);
|
|
||||||
contextBridge.exposeInMainWorld('events', affineApis.events);
|
|
||||||
contextBridge.exposeInMainWorld('appInfo', affineApis.appInfo);
|
|
||||||
|
|||||||
@@ -9,3 +9,26 @@ if (config.enablePlugin && !environment.isServer) {
|
|||||||
if (!environment.isServer) {
|
if (!environment.isServer) {
|
||||||
import('@affine/bookmark-block');
|
import('@affine/bookmark-block');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!environment.isDesktop && !environment.isServer) {
|
||||||
|
// Polyfill Electron
|
||||||
|
const unimplemented = () => {
|
||||||
|
throw new Error('AFFiNE Plugin Web will be supported in the future');
|
||||||
|
};
|
||||||
|
const affine = {
|
||||||
|
ipcRenderer: {
|
||||||
|
invoke: unimplemented,
|
||||||
|
send: unimplemented,
|
||||||
|
on: unimplemented,
|
||||||
|
once: unimplemented,
|
||||||
|
removeListener: unimplemented,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.freeze(affine);
|
||||||
|
|
||||||
|
Object.defineProperty(window, 'affine', {
|
||||||
|
value: affine,
|
||||||
|
writable: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { useCallback, useEffect, useRef } from 'react';
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
interface IPCRenderer {
|
||||||
|
send(channel: string, ...args: any[]): void;
|
||||||
|
invoke(channel: string, ...args: any[]): Promise<any>;
|
||||||
|
on(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: unknown, ...args: any[]) => void
|
||||||
|
): this;
|
||||||
|
once(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: unknown, ...args: any[]) => void
|
||||||
|
): this;
|
||||||
|
removeListener(channel: string, listener: (...args: any[]) => void): this;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
affine: {
|
||||||
|
ipcRenderer: IPCRenderer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe
|
||||||
|
*/
|
||||||
|
export function useAffineAsyncCallback(channel: string) {
|
||||||
|
return useCallback(
|
||||||
|
(...args: any[]): Promise<any> => {
|
||||||
|
return window.affine.ipcRenderer.invoke(channel, ...args);
|
||||||
|
},
|
||||||
|
[channel]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe
|
||||||
|
*/
|
||||||
|
export function useAffineListener(
|
||||||
|
channel: string,
|
||||||
|
listener: (event: unknown, ...args: any[]) => void,
|
||||||
|
once?: boolean
|
||||||
|
): void {
|
||||||
|
const fnRef = useRef<((event: unknown, ...args: any[]) => void) | null>(null);
|
||||||
|
if (!fnRef.current) {
|
||||||
|
fnRef.current = listener;
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
if (once) {
|
||||||
|
window.affine.ipcRenderer.once(channel, fnRef.current!);
|
||||||
|
} else {
|
||||||
|
window.affine.ipcRenderer.on(channel, fnRef.current!);
|
||||||
|
}
|
||||||
|
return () => {
|
||||||
|
window.affine.ipcRenderer.removeListener(channel, fnRef.current!);
|
||||||
|
};
|
||||||
|
}, [channel, once]);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user