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官网

相关推荐
September_ning3 小时前
React.lazy() 懒加载
前端·react.js·前端框架
晴天飛 雪3 小时前
React 守卫路由
前端框架·reactjs
web行路人3 小时前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
~甲壳虫5 小时前
说说webpack中常见的Plugin?解决了什么问题?
前端·webpack·node.js
~甲壳虫6 小时前
说说webpack中常见的Loader?解决了什么问题?
前端·webpack·node.js
~甲壳虫6 小时前
说说webpack proxy工作原理?为什么能解决跨域
前端·webpack·node.js
一ge科研小菜鸡6 小时前
React前端框架:现代网页开发的基石(附带构建简单任务管理应用案例代码)
前端框架
熊的猫7 小时前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
前端青山16 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
GDAL18 小时前
npm入门教程1:npm简介
前端·npm·node.js