examples: Update Electron Typescript Example with Best Practices (#58947)
Co-authored-by: Lee Robinson <me@leerob.io>
This commit is contained in:
parent
92f7d0c5e9
commit
d509c2d528
7 changed files with 35 additions and 34 deletions
|
@ -1,6 +1,6 @@
|
|||
# Electron with Typescript application example
|
||||
|
||||
This example show how you can use Next.js inside an Electron application to avoid a lot of configuration, use Next.js router as view and use server-render to speed up the initial render of the application. Both Next.js and Electron layers are written in TypeScript and compiled to JavaScript during the build process.
|
||||
This example shows how to use Next.js inside an Electron application. To avoid a lot of configuration, we use Next.js as a router for pages, and use server rendering to speed up the initial render of the application. Both Next.js and Electron layers are written in TypeScript and compiled to JavaScript during the build process.
|
||||
|
||||
| Part | Source code (Typescript) | Builds (JavaScript) |
|
||||
| ---------- | ------------------------ | ------------------- |
|
||||
|
@ -8,7 +8,7 @@ This example show how you can use Next.js inside an Electron application to avoi
|
|||
| Electron | `/electron-src` | `/main` |
|
||||
| Production | | `/dist` |
|
||||
|
||||
For development it's going to run a HTTP server and let Next.js handle routing. In production it use `output: 'export'` to pre-generate HTML static files and use them in your app instead of running an HTTP server.
|
||||
For development it's going to run a HTTP server and let Next.js handle routing. In production it will use `output: 'export'` to pre-generate HTML static files and use them in your app (instead of running a HTTP server).
|
||||
|
||||
## How to use
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ app.on('ready', async () => {
|
|||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: false,
|
||||
contextIsolation: false,
|
||||
contextIsolation: true,
|
||||
preload: join(__dirname, 'preload.js'),
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,17 +1,16 @@
|
|||
/* eslint-disable @typescript-eslint/no-namespace */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { ipcRenderer, IpcRenderer } from 'electron'
|
||||
import { contextBridge, ipcRenderer } from 'electron'
|
||||
import { IpcRendererEvent } from 'electron/main'
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
ipcRenderer: IpcRenderer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since we disabled nodeIntegration we can reintroduce
|
||||
// needed node functionality here
|
||||
process.once('loaded', () => {
|
||||
global.ipcRenderer = ipcRenderer
|
||||
// We are using the context bridge to securely expose NodeAPIs.
|
||||
// Please note that many Node APIs grant access to local system resources.
|
||||
// Be very cautious about which globals and APIs you expose to untrusted remote content.
|
||||
contextBridge.exposeInMainWorld('electron', {
|
||||
sayHello: () => ipcRenderer.send('message', 'hi from next'),
|
||||
receiveHello: (handler: (event: IpcRendererEvent, ...args: any[]) => void) =>
|
||||
ipcRenderer.on('message', handler),
|
||||
stopReceivingHello: (
|
||||
handler: (event: IpcRendererEvent, ...args: any[]) => void
|
||||
) => ipcRenderer.removeListener('message', handler),
|
||||
})
|
||||
|
|
|
@ -13,20 +13,20 @@
|
|||
"type-check": "tsc -p ./renderer/tsconfig.json && tsc -p ./electron-src/tsconfig.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"electron-is-dev": "^1.1.0",
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-next": "^3.1.5",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.6",
|
||||
"@types/react": "^16.9.9",
|
||||
"@types/react-dom": "^16.9.9",
|
||||
"electron": "^13",
|
||||
"electron-builder": "^23.0.3",
|
||||
"@types/node": "^14.18.63",
|
||||
"@types/react": "^16.14.52",
|
||||
"@types/react-dom": "^16.9.24",
|
||||
"electron": "^27.1.2",
|
||||
"electron-builder": "^24.9.1",
|
||||
"next": "latest",
|
||||
"rimraf": "^3.0.0",
|
||||
"typescript": "^4.0.5"
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"build": {
|
||||
"asar": true,
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
//
|
||||
// import User from 'path/to/interfaces';
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
import { IpcRenderer } from 'electron'
|
||||
|
||||
declare global {
|
||||
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
ipcRenderer: IpcRenderer
|
||||
interface Window {
|
||||
electron: {
|
||||
sayHello: () => void
|
||||
receiveHello: (handler: (event, args) => void) => void
|
||||
stopReceivingHello: (handler: (event, args) => void) => void
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,16 +6,16 @@ const IndexPage = () => {
|
|||
useEffect(() => {
|
||||
const handleMessage = (_event, args) => alert(args)
|
||||
|
||||
// add a listener to 'message' channel
|
||||
global.ipcRenderer.addListener('message', handleMessage)
|
||||
// listen to the 'message' channel
|
||||
window.electron.receiveHello(handleMessage)
|
||||
|
||||
return () => {
|
||||
global.ipcRenderer.removeListener('message', handleMessage)
|
||||
window.electron.stopReceivingHello(handleMessage)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onSayHiClick = () => {
|
||||
global.ipcRenderer.send('message', 'hi from next')
|
||||
window.electron.sayHello()
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -12,8 +12,9 @@
|
|||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
"jsx": "preserve",
|
||||
"incremental": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../next.config.js"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue