examples: Update Electron Typescript Example with Best Practices (#58947)

Co-authored-by: Lee Robinson <me@leerob.io>
This commit is contained in:
Dylan700 2023-11-30 13:37:03 +11:00 committed by GitHub
parent 92f7d0c5e9
commit d509c2d528
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 35 additions and 34 deletions

View file

@ -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

View file

@ -16,7 +16,7 @@ app.on('ready', async () => {
height: 600,
webPreferences: {
nodeIntegration: false,
contextIsolation: false,
contextIsolation: true,
preload: join(__dirname, 'preload.js'),
},
})

View file

@ -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),
})

View file

@ -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,

View file

@ -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
}
}
}

View file

@ -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 (

View file

@ -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"]
}