Electron快速上手

什么是Electron

  • 一款应用广泛的跨平台的桌面应用开发框架。
  • Electron的本质是结合了 Chromium 与Node.js。
  • 使用HTML、CSS、JS 等Web技术构建桌面应用程序。
    • .vue,.tsx,.less,.ts也可以使用

Electron 流程模型

  • 主进程是纯node环境,可以访问__dirname,fs模块等,不能访问alert(),window等
  • 渲染进程可以访问alert(),window等,不能访问__dirname,fs模块等
  • 一个主进程可以管理多个渲染进程,渲染进程能够与主进程沟通
  • 主进程可以调用原生api

创建应用程序

Electron 应用程序遵循与其他 Node.js 项目相同的结构。 首先创建一个文件夹并初始化 npm 包。

bash 复制代码
mkdir my-electron-app && cd my-electron-app
npm init

init初始化命令会提示您在项目初始化配置中设置一些值 为本教程的目的,有几条规则需要遵循:

  • entry point 应为 main.js.
  • authordescription 可为任意值,但对于应用打包是必填项。

你的 package.json 文件应该像这样:

javascript 复制代码
{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "Hello World!",
  "main": "main.js",
  "author": "Jane Doe",
  "license": "MIT"
}

然后,将 electron 包安装到应用的开发依赖中。

bash 复制代码
npm install --save-dev electron

创建main.js

就可以通过npm start运行程序

简单程序制作

展示网页信息
javascript 复制代码
//main.js

const {app,BrowserWindow} = require('electron')

app.on('ready',()=>{// 当app准备好的时候调用回调
    const win = new BrowserWindow({//创建窗口
        width:800,
        height:600,
        autoHideMenuBar:true,//隐藏默认配置菜单
        x:0,
        y:0,//在什么位置打开
        alwaysOnTop:true//一直置顶,不被遮挡
    })
    win.loadURL('https://blog.csdn.net/m0_56772756?type=blog')//加载远程页面
})
展示个人页面
html 复制代码
//html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <h1>学习electron开发</h1>
</body>
</html>


//index.css
h1{
    background-color: aquamarine ;
    color: purple;
}
javascript 复制代码
const {app,BrowserWindow} = require('electron')

app.on('ready',()=>{// 当app准备好的时候调用回调
    const win = new BrowserWindow({//创建窗口
        width:800,
        height:600,
        autoHideMenuBar:true,//隐藏默认配置菜单
        x:0,
        y:0,//在什么位置打开
        alwaysOnTop:true//一直置顶,不被遮挡
    })
    // win.loadURL('http://www.atguigu.com')//加载页面
    // 加载文件
    win.loadFile('./pages/index.html')
})

npm start执行程序

终端出现警告(可忽略)

内容安全策略

在页面中运行ctrl+shift+i查看开发者工具

出现警告​​​​内容安全策略(CSP)给html文件添加meta标签,配置CSP(Content-Security-Policy)

html 复制代码
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self';style-src 'self' 'unsafe-inline';img-src 'self' ">

部分配置说明

  1. default-src 'self'
  • default-src:配置加载策略,适用于所有未在其它指令中明确指定的资源类型。
  • self:仅允许从同源的资源加载,禁止从不受信任的外部来源加载,提高安全性。
  1. style-src 'self' ' unsafe-inline
  • style-src:指定样式表(CSS)的加载策略。
  • self:仅允许从同源的资源加载,禁止从不受信任的外部来源加载,提高安全性。
  • unsafe-inline :允许在HTML文档内使用内联样式。
  1. img-src 'self' data:
  • img-src:指定图像资源的加载策略。
  • self:表示仅允许从同源加载图像。
  • data::允许使用data: URI来嵌入图像。这种URI模式允许将图像数据直接嵌入到HTML或CSS中,而不是通过外部链接引用。

了解更多查看:​​​​内容安全策略(CSP)

完善窗口行为
  1. Windows和Linux平台窗口特点是:关闭所有窗口时退出应用。
javascript 复制代码
app.on('window-all-closed', () => {//当所有窗口都关闭的时候
  if (process.platform !== 'darwin') app.quit()//如果不是苹果系统Mac(darwin),退出应用
})
  1. mac应用即使在没有打开任何窗口的情况下也继续运行,并且在没有窗口可用的情况下激活应用时会打开新的窗口。
javascript 复制代码
//当app准备好后,执行createwindow创建窗口
app.on( 'ready' ,()=>{
    createwindow()//当应用被激活时
    app.on( 'activate', ()=>{
    //如果当前应用没有窗口,则创建一个新的窗口
    if (Browserwindow.getAllwindows().length === 0) createwindow()
    })
})

更多窗口行为查看:BrowserWindow | Electron (electronjs.org)

配置自动重启
bash 复制代码
npm i nodemon -d

修改package.json配置

javascript 复制代码
"start": "nodemon --exec electron ."

此配置只实现了mian.js的修改触发自动重启,页面的修改不能实现自动重启

配置nodemon.json规则

javascript 复制代码
{
    "'ignore":[
        "node_modules",
        "dist"
    ],
    "restartable":"r",
    "watch":["*.*"],
    "ext":"html,js,css"
}

"restartable":"r",是配置短命令 ,在终端命令行中输入r实现程序自动重启

配置好以后,当代码修改后,应用就会自动重启了。

electron控制台打印乱码

修改package.json文件

javascript 复制代码
  "start": "chcp 65001 && nodemon --exec electron ."

主进程与渲染进程

主进程与渲染进程个分隔开

主进程

每个Electron应用都有一个唯一的主进程,作为应用程序的入口点(main.js)。主进程在Node.js环境中运行,它具有require模块和使用所有Node.js API的能力,主进程的核心就是:使用BrowserWindow来创建和管理窗口。无法访问浏览器函数。

主进程(main.js)不能访问window、alert之类的

渲染进程

每个BrowserWindow实例都对应一个单独的渲染器进程(多个渲染进程 ),运行在渲染器进程中的代码,必须遵守网页标准,这也就意味着:渲染器进程无权直接访问require或使用任何Node.js的API。

问题产生:处于渲染器进程的用户界面,该怎样才与Node.js和Electron的原生桌面功能进行交互呢?

Preload脚本

预加载(Preload)脚本是运行在渲染进程中的,但它是在网页内容加载之前执行的,这意味着它具有比普通渲染器代码更高的权限,可以访问Node.js的 API,同时又可以与网页内容进行安全的交互。

简单说:它是Node.jsWeb APl 的桥梁,Preload 脚本可以安全地将部分Node.js功能暴露给网页,从而减少安全风险。

在渲染进程(浏览器环境)中中运行

需求:点击按钮后,在页面呈现当前的Node 版本。

preload.js文件不能直接触发,需要在main.js中定义

执行顺序:主进程 -> 预加载脚本 -> 渲染进程

prload可访问api
可用的 API 详细信息
Electron 模块 渲染进程模块
Node.js 模块 eventstimersurl
Polyfilled 的全局模块 BufferprocessclearImmediatesetImmediate
暴露Electron 的 process.versions 对象给渲染器
javascript 复制代码
//预加载脚本 preload.js
const { contextBridge  } =require ('electron')


console.log('preload')

contextBridge.exposeInMainWorld('toRenderVersions',{//对外暴露一个toRenderVersions全局变量,是渲染进程可以获取
    node:()=>process.versions.node,//node版本
    chrome:()=>process.versions.chrome,
    electron:()=>process.versions.electron
})
javascript 复制代码
//main.js

const {app,BrowserWindow} = require('electron')
const path = require('node:path')//node的path方法

function createWindow(){
    const win = new BrowserWindow({//创建窗口
        width:800,
        height:600,
        autoHideMenuBar:true,//隐藏默认配置菜单
        x:0,
        y:0,//在什么位置打开
        webPreferences:{// 网页功能设置
            preload:path.join(__dirname,'./preload.js')
        }
    })
    // 加载文件
    win.loadFile('./pages/index.html')
}

app.on('ready',()=>{// 当app准备好的时候调用回调
    console.log('应用准备完毕!!!')
    createWindow()
    app.on('activate', () => {//应用被激活的时候(仅针对苹果系统)
    if (BrowserWindow.getAllWindows().length === 0) createWindow() // 当前窗口数量是0 ,没有窗口,就创建窗口
    })
})

这里使用了两个Node.js概念:

  • __dirname 字符串指向当前正在执行的脚本的路径(在本例中,它指向你的项目的根文件夹)。
  • path.join API 将多个路径联结在一起,创建一个跨平台的路径字符串。

现在渲染器能够全局访问 versions 了,让我们快快将里边的信息显示在窗口中。 这个变量不仅可以通过 window.versions 访问,也可以很简单地使用 versions 来访问。 新建一个 renderer.js 脚本, 使用 document.getElementById DOM API 来替换 id 属性为 info 的 HTML 元素的文本。

javascript 复制代码
//render.js
// 执行在渲染进程中
const btn1 = document.getElementById('btn1')

btn1.onclick = ()=>{
    alert('此应用的node版本'+toRenderVersions.node()+'chrome版本'+toRenderVersions.chrome()+'electron版本'+toRenderVersions.electron())
}

进程之间通信(IPC)

1. 渲染进程->主进程(单向)

概述:在渲染器进程中ipcRenderer.send发送消息在主进程中使用ipcMain.on接收消息。

常用于:在 Web中调用主进程的API,例如下面的这个需求:

需求:点击按钮后,在用户的D盘创建一个hello.txt文件,文件内容来自于用户输入。

1.页面中添加相关元素,render.js中添加对应脚本

html 复制代码
    <input id="input" type="text">
    <button id="btn2"> 向d盘写入hello.txt</button>
javascript 复制代码
const btn2=document.getElementById('btn2')
const input=document.getElementById('input')

btn2.onclick=()=>{
    toRenderVersions.saveFile(input.value)
}
  1. preload.js 中使用ipcRenderer.invoke('信道',参数)发送消息,与主进程通信。
javascript 复制代码
//预加载脚本
const { contextBridge ,ipcRenderer } =require ('electron') 

contextBridge.exposeInMainWorld('toRenderVersions',{
    saveFile:(data)=>{
        // 传入参数:信道,数据
        ipcRenderer.send('file-save',data)
    }
})

3.主进程main.js使用ipcMain.on('信道',()=>{})收到消息,触发函数执行

javascript 复制代码
const {app,BrowserWindow,ipcMain} = require('electron')

function writeFile(_,data){
    fs.writeFileSync('D:/hello.txt',data)
}

function createWindow(){
    const win = new BrowserWindow({//创建窗口
        width:800,
        height:600,
        autoHideMenuBar:true,//隐藏默认配置菜单
        webPreferences:{// 网页功能设置,web首选项
            preload:path.join(__dirname,'./preload.js')//绝对路径
        }
    })

    ipcMain.on('file-save',writeFile)//send对应on
    win.loadFile('./pages/index.html')
}

2.主进程与渲染进程的双向通信

概述:渲染进程通过ipcRenderer.invoke 发送消停,主进程使用ipcMain.handle接收并处理消息。

备注:ipcRender.invoke的返回值是Promise实例

常用于:从渲染器进程调用主进程方法并等待结果,例如下面的这个需求:

需求:点击按钮从D盘读取hello.txt中的内容,并将结果呈现在页面上。

1.页面中添加相关元素,render.js中添加对应脚本

html 复制代码
   <button id="btn3">读取D盘中的hello.txt</button>
javascript 复制代码
const btn3=document.getElementById('btn3')
btn3.onclick=async()=>{
    let fileContent =await toRenderVersions.readFile()
    console.log(fileContent)
    alert(fileContent)
}
  1. preload.js中使用ipcRenderer.invoke( '信道',参数)发送消息,与主进程通信。
javascript 复制代码
//预加载脚本
const { contextBridge ,ipcRenderer } =require ('electron') 

contextBridge.exposeInMainWorld('toRenderVersions',{
    readFile:()=>{
        //传入参数:信道,(数据)
        return ipcRenderer.invoke('file-read')//调用,渲染进程与主进程的双向通信
    }
})

3.主进程main.js使用ipcMain.handle('信道',()=>{})接收消息,并执行函数返回数据

javascript 复制代码
const {app,BrowserWindow,ipcMain} = require('electron')
const path = require('node:path')//node的path模块
const fs = require('fs')

function readFile(){
    console.log( fs.readFileSync('D:/hello.txt'),fs.readFileSync('D:/hello.txt').toString())
    return fs.readFileSync('D:/hello.txt').toString()
}

function createWindow(){
    const win = new BrowserWindow({//创建窗口
        width:800,
        height:600,
        autoHideMenuBar:true,//隐藏默认配置菜单
        webPreferences:{// 网页功能设置,web首选项
            preload:path.join(__dirname,'./preload.js')//绝对路径
        }
    })
    ipcMain.handle('file-read',readFile)//invoke对应handle
    win.loadFile('./pages/index.html')
}

3.主进程->渲染进程(单项通信)

概述:主进程使用win.webContents.send发送消息,渲染进程通过ipcRenderer.on处理消息,

常用于:从主进程主动发送消息给渲染进程,例如下面的这个需求:

需求:应用加载6秒钟后,主动给渲染进程发送一个消息,内容是:你好啊!

1.页面中添加相关元素,render.js 中添加对应脚本

javascript 复制代码
window.onload=()=>{
    toRenderVersions.getMessage(logMessage)
}

const logMessage = (event,str)=>{
    console.log(event,str)
}

2.preload.js中使用ipcRenderer.on('信道',回调)接收消息,并配置回调函数.

javascript 复制代码
getMessage:(callback)=>{
    return ipcRenderer.on('message',callback)
}

3.主进程中,在合适的时候,使用win.webContents.send('信道',数据)发送消息。

javascript 复制代码
// 加载了本地页面后,创建一个定时器
setTimeout(() => {
    win.webContents.send('message','你好啊')
}, 6000);

渲染进程与渲染进程之间不能直接通信,需要通过主进程传递数据

打包应用

使用electron-builder打包应用

1.安装electron-builder :

bash 复制代码
npm install electron-builder -D

2.在package.json中进行相关配置,具体配置如下

备注:json文件不支持注释,使用时请去掉所有注释。

javascript 复制代码
{
  "name": "my-electron-app",//应用程序的名称
  "version": "1.0.0",//应用程序的版本
  "description": "my first electron app",//应用程序的描述
  "main": "main.js",//应用程序入口文件
  "scripts": {
    "start": "chcp 65001 && nodemon --exec electron .",//使用`electron .`命令启动应用程序
    "build":"electron-builder"//使用`electron-builder`打包应用程序,生成安装包
  },
  "build":{
    "appId":"com.ylx.hahaha",//应用程序唯一标识符
    //打包windows平台安装包的具体配置
    "win":{
      "icon":"./logo.ico",//应用图标
      "target":[
        {
          "target":"nsis",//指定使用 NSIS 作为安装程序格式(.exe安装包文件)
          "arch":["x64"]//生成64 位安装包
        }
      ]
    },
    "nsis":{
      "oneClick":false,//设置为`false`使安装程序显示安装向导界面,而不是一键安装
      "perMachine":true,//允许每台机器安装一次,而不是每个用户都安装
      "allowToChangeInstallationDirectory":true//允许用户在安装过程中选择安装目录
    }
  },
  "author": "ylx",//作者信息
  "license": "ISC",//许可证信息
  "devDependencies": {
    "electron": "^32.0.1",//开发依赖中的Electron版本
    "electron-builder": "^24.13.3"//开发依赖中的'electron-builder'版本
  },
  "dependencies": {
    "nodemon": "^3.1.4"
  }
}

执行打包命令:

bash 复制代码
npm run build

electron-vite

electron-vite 是一个新型构建工具,旨在为 Electron 提供更快、更精简的开发体验。它主要由五部分组成:

  • 一套构建指令,它使用 Vite 打包你的代码,并且它能够处理 Electron 的独特环境,包括 Node.js 和浏览器环境。

  • 集中配置主进程、渲染器和预加载脚本的 Vite 配置,并针对 Electron 的独特环境进行预配置。

  • 为渲染器提供快速模块热替换(HMR)支持,为主进程和预加载脚本提供热重载支持,极大地提高了开发效率。

  • 优化 Electron 主进程资源处理。

  • 使用 V8 字节码保护源代码。

electron-vite 需要 Node.js 版本 18+,20+ 和 Vite 版本 4.0+

更多electron-vite信息:electron-vite官网

相关推荐
没事别瞎琢磨2 小时前
十一、审计与 Run Session——每一步操作都被记录
人工智能·node.js
没事别瞎琢磨2 小时前
十六、AgentSandbox——把所有模块串起来的编排类
人工智能·node.js
没事别瞎琢磨2 小时前
十二、网络代理与白名单规则引擎
人工智能·node.js
没事别瞎琢磨2 小时前
十四、Git Worktree 隔离执行
人工智能·node.js
没事别瞎琢磨3 小时前
十、统一 Runner 入口——能力检测与模式回退
人工智能·node.js
没事别瞎琢磨3 小时前
八、环境隔离——构建安全的子进程环境
人工智能·node.js
没事别瞎琢磨4 小时前
六、输出捕获与截断
人工智能·node.js
没事别瞎琢磨5 小时前
七、敏感路径预检——Protected Paths
人工智能·node.js
没事别瞎琢磨5 小时前
五、进程执行——spawn、超时与进程树清理
人工智能·node.js
没事别瞎琢磨5 小时前
四、命令风险分级与审批策略
人工智能·node.js