主进程和渲染进程

主进程:启动项目运行时的入口文件main.js脚本就是我们说的主进程。

  • 在主进程运行的脚本可以创建Web页面形式展示GUI。

  • 主线程只有一个

渲染进程:每个Electron的页面都在运行着自己的进程,这样的进程称之为渲染进程(基于Chromium的多进程结构)。

主进程通过IPC通信与多个渲染进程(Web页面)通信(每个渲染进程都有一条与主线程IPC通信)

  • 双向IPC通信

  • 一对多(类似于映射)

mainProcess_renderingProcess

主进程使用 BrowserWindow 创建实例,主进程销毁后,对应的渲染进程会被终止。主进程与渲染进程通过 IPC 方式(事件驱动)进行通信。

为什么主进程与渲染进程的node.js是分开的?

不分开,客户可以在HTML代码里,直接访问node.js里的文件,(自创本地磁盘文件,Horrible!)

将主线程与渲染进程的node.js打通1-不用

  • 在根目录下建文件夹,里建js文件

  • js文件里使用node语法(app.js)

  • 在html引入路径(script标签)

//app.js
const fs = require('fs')
//fs.writeFile('路径/文件名.什么类的','内容')
fs.writeFile('E:\Downloads\git\blog\abc.txt','abc',()=>{console.log('done.')})
//在该路径下会建一个abc.txt文件,里面的内容是abc
  • 打通代码,入口文件里写
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
  • 具体位置
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
contextIsolation: false
}
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
}
app.whenReady().then(createWindow)

将主线程与渲染进程的node.js打通2-可用

preload.js在启动应用时在渲染进程里预加载js

  • 做个桥,渲染前,先预加载
  • 不让你在渲染进程直接用node,在预加载可以实现
  • 在根目录下建preload.js,然后在文件入口引入
  • 直接引入会报错

preload

  • 需要用node.js方法请求绝对路径
const path = require('path')

webPreferences: {
// dirname当前入口文件的绝对物理路径+相对路径
preload: path.resolve(__dirname, './preload.js')
}
  • 具体位置
const path = require('path')
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// dirname当前入口文件的绝对物理路径+相对路径
preload: path.resolve(__dirname, './preload.js')
}
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
}

app.whenReady().then(createWindow)

将process(node)渲染在页面上

  • 用桥contextBridge,在preload中注入变量,让我们在页面上可使用process

  • 主进程里定义好东西,挂在window对象上,使渲染进程可以访问

    //preload.js
    const { contextBridge } = require('electron')
    //myApi是接口(任意取),后面是接口里的值
    contextBridge.exposeInMainWorld('myApi', {
    platform : process.platform,
    desktop: true
    })

  • 渲染进程app.js文件

console.log(window.myApi.platform)

在electron窗口打开开发者工具

  • 在入口文件main.js
 // 打开开发者工具
win.webContents.openDevTools()
  • 具体位置
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
}
app.whenReady().then(createWindow)

安全警告

safety warning

方式一:警告全干掉

  • 不提倡,会看不到安全隐患
// 暂时关闭安全警告
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
  • 具体位置
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
// 暂时关闭安全警告
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'
}
app.whenReady().then(createWindow)

方式二:csp配置浏览器判断

  • 在渲染进程里
 <!--配置CSP,内部导入,啥都是本地的-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;
script-src 'self'; style-src 'self' 'unsafe-inline'">
  • 具体位置
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!--配置CSP-->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data:;
script-src 'self'; style-src 'self' 'unsafe-inline'">
<title>Document</title>
</head>
<body>
hello
<script src="./render/app.js"></script>
</body>
</html>

主进程事件生命周期

声明周期函数

窗口关闭后,桌面是否有,图标

关闭后,没有

  • 代码
app.on('window-all-closed', () =. {
console.log('window-all-closed')
// 对于 MacOS 系统 -? 关闭窗口时,不会直接推出应用
//process主进程
//platform平台
// darwin:Mac系统
if (process.platform == 'darwin') {
//关闭停止
app.quit()
}
})
  • 具体位置
//main.js入口文件
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
}

app.on('window-all-closed', () => {
if (process.platform == 'darwin') {
app.quit()
}
})

app.whenReady().then(createWindow)

关闭后,有

  • 代码
app.whenReady().then(() =. {
createWindow()
// 在MacOS下,当全部窗口关闭,点击 dock 图标,窗口再次打开。
app.on('activate', () =>{
if (BrowserWindow.getAllWindows().length ==0) {
createWindow()
}
})
})
  • 具体位置(有个bug,可能没效果)
//main.js入口文件
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
// 在MacOS下,当全部窗口关闭,点击 dock 图标,窗口再次打开。
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length == 0) {
createWindow()
}
})
}

app.whenReady().then(createWindow)
  • 完整
const path = require('path')
const { app, BrowserWindow } = require('electron')
// 主进程
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,

})
win.loadFile('./index.html')
// win.loadURL('./index.html')
// 打开开发者工具
win.webContents.openDevTools()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length == 0) {
createWindow()
}
})
}

app.on('window-all-closed', () => {
if (process.platform == 'darwin') {
app.quit()
}
})

app.whenReady().then(createWindow)

总结

主、渲染进程的关系,有主,渲染的原因,主线程桌面图标的关闭,安全警告处理csp配置,调试工具打开发方式

contextBridge作为桥将主进程与渲染进程联系起来,主、渲染进程有安全隔离用预加载方式访问和调用node.js模块,这个方式只将主进程对象给了渲染进程。

preload主进程里定义好东西,挂在window对象上,使渲染进程可以访问