摸鱼无聊怎么办,怼着代码死里干!
为了接触更多的新技术,拓展自己的技术能力,本文给大家带来我第一次使用electron的技术文章,记录了对electron的一些基本的认识,主要介绍了electron的一些基本的架构和api的使用,由于对react的熟悉度还是比较低,所以这次选择的脚手架是electron-react
快速安装
先简单引入一段 electron-react-boilerplate 的安装模版
            
            
              js
              
              
            
          
          # Clone the boilerplate:  
git clone --depth=1 \  
https://github.com/electron-react-boilerplate/electron-react-boilerplate \  
your-project-name  
  
cd your-project-name  
  
# Install dependencies:  
npm install
        先看最终运行效果

安装问题
将项目克隆到本地后会出现无法安装的报错

解决方案
- 清理 
npm缓存: 尝试清理npm的缓存,运行以下命令来清理npm缓存: 
            
            
              js
              
              
            
          
          npm cache clean --force
        - 删除 
node_modules和package-lock.json: 有时候,node_modules和package-lock.json中的一些缓存或冲突可能导致问题。需要尝试删除它们并重新安装依赖: 
            
            
              js
              
              
            
          
          rmdir /s /q node_modules 
del package-lock.json 
npm install
        - 重新运行即可解决问题
 
electron结构
我们先简单了解一下 electron 主要分为主进程和渲染进程 为了下面的代码解析做一个基础

主进程

"main": "./src/main/main.ts" 是在 package.json 文件中指定 Electron 应用程序主进程(Main Process)入口文件的配置。
渲染进程
在主窗口载入渲染进程页面
            
            
              js
              
              
            
          
          //main
  mainWindow.loadURL(resolveHtmlPath('index.html'));
        
            
            
              js
              
              
            
          
          export function resolveHtmlPath(htmlFileName: string) {
  if (process.env.NODE_ENV === 'development') {
    const port = process.env.PORT || 1212;
    const url = new URL(`http://localhost:${port}`);
    url.pathname = htmlFileName;
    return url.href;
  }
  return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`;
}
        通过该方式将渲染进程加载到窗口中
主进程解读
1.导入依赖
首先导入了一些 Electron 相关的模块,包括path、app、BrowserWindow、shell和ipcMain等。还导入了其他模块,如electron-updater用于自动更新应用、electron-log用于记录日志等。
            
            
              js
              
              
            
          
          import path from 'path';
import { app, BrowserWindow, shell, ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import log from 'electron-log';
import MenuBuilder from './menu';
import { resolveHtmlPath } from './util';
        主进程和渲染进程通信
上面导入的ipcMain主要是用于主进程和渲染进程之间的通信
主进程监听了名为 'ipc-example' 的 IPC 事件。当渲染进程发送 'ipc-example' 事件时,主进程将打印接收到的消息,并回复 'ipc-example' 事件,回复内容为 'IPC test: pong'。
            
            
              js
              
              
            
          
          //main
ipcMain.on('ipc-example', async (event, arg) => {
  const msgTemplate = (pingPong: string) => `IPC test: ${pingPong}`;
console.log(msgTemplate(arg),'收到渲染进程信息');
  event.reply('ipc-example', msgTemplate('pong'));
});
        
            
            
              js
              
              
            
          
          /renderer
// calling IPC exposed from preload script
window.electron.ipcRenderer.once('ipc-example', (arg) => {
  // eslint-disable-next-line no-console
    console.log(arg,'收到主进程信息');
});
        渲染进程的打印在启动窗口中打印 
主进程在vscode控制台打印,我们可以看到已经接收到渲染进程发送的信息,但是结果是乱码

解决控制台乱码 :
启动的命令中加上 chcp 65001
            
            
              js
              
              
            
          
          "start": "chcp 65001 && ts-node ./.erb/scripts/check-port-in-use.js && npm run start:renderer",
        
开发环境配置
代码中检查了环境变量 NODE_ENV 和 DEBUG_PROD,以确定是否为开发环境。如果是开发环境,会调用 electron-debug 模块来支持 Electron 的开发调试。
            
            
              js
              
              
            
          
          const isDebug =
  process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true';
if (isDebug) {
  require('electron-debug')();
}
        安装开发者工具扩展: 在开发环境下,通过 electron-devtools-installer 模块来安装开发者工具扩展,其中包括 REACT_DEVELOPER_TOOLS。
            
            
              js
              
              
            
          
          const installExtensions = async () => {
  const installer = require('electron-devtools-installer');
  const forceDownload = !!process.env.UPGRADE_EXTENSIONS;
  const extensions = ['REACT_DEVELOPER_TOOLS'];
  return installer
    .default(
      extensions.map((name) => installer[name]),
      forceDownload
    )
    .catch(console.log);
};
        
创建主窗口
createWindow 函数用于创建 Electron 主窗口。这里定义了主窗口的属性,包括尺寸、图标、preload 脚本等,并加载 index.html 页面。在主窗口准备好显示后,会显示主窗口,也可以选择最小化窗口。
isDebug:isDebug是一个布尔值,表示是否处于调试模式。如果是调试模式,则会执行installExtensions函数,安装开发工具扩展。RESOURCES_PATH和getAssetPath:这两个变量用于确定资源文件的路径。RESOURCES_PATH是一个字符串,表示资源文件夹的路径。getAssetPath是一个函数,接受一个或多个路径片段,然后返回它们在资源文件夹中的完整路径。mainWindow:mainWindow是一个 ElectronBrowserWindow对象,用于创建和管理应用程序的主窗口。在这个函数中,它会被创建并设置一些属性,如窗口大小、图标、预加载脚本等。mainWindow.loadURL:该方法用于加载应用程序的主页面,它会将指定的 HTML 文件加载到mainWindow窗口中。mainWindow.on('ready-to-show'):该事件监听器会在mainWindow窗口加载完毕并准备好显示时触发。在这里,它会检查mainWindow是否为 null,并根据process.env.START_MINIMIZED的值决定是最小化窗口还是显示窗口。mainWindow.on('closed'):该事件监听器会在mainWindow窗口关闭时触发,用于清理资源并将mainWindow设置为 null。menuBuilder.buildMenu():这是一个用于创建应用程序菜单的函数,将在mainWindow中创建自定义菜单。mainWindow.webContents.setWindowOpenHandler():这是一个用于处理应用程序中链接的函数。它会在用户点击链接时打开默认浏览器,而不是在 Electron 中打开新窗口。
            
            
              js
              
              
            
          
          const createWindow = async () => {
  if (isDebug) {
    await installExtensions();
  }
  const RESOURCES_PATH = app.isPackaged
    ? path.join(process.resourcesPath, 'assets')
    : path.join(__dirname, '../../assets');
  const getAssetPath = (...paths: string[]): string => {
    return path.join(RESOURCES_PATH, ...paths);
  };
  mainWindow = new BrowserWindow({
    show: false,
    width: 1024,
    height: 728,
    icon: getAssetPath('icon.png'),
    webPreferences: {
      preload: app.isPackaged
        ? path.join(__dirname, 'preload.js')
        : path.join(__dirname, '../../.erb/dll/preload.js'),
    },
  });
  mainWindow.loadURL(resolveHtmlPath('index.html'));
  mainWindow.on('ready-to-show', () => {
    if (!mainWindow) {
      throw new Error('"mainWindow" is not defined');
    }
    if (process.env.START_MINIMIZED) {
      mainWindow.minimize();
    } else {
      mainWindow.show();
    }
  });
  mainWindow.on('closed', () => {
    mainWindow = null;
  });
  const menuBuilder = new MenuBuilder(mainWindow);
  menuBuilder.buildMenu();
  // Open urls in the user's browser
  mainWindow.webContents.setWindowOpenHandler((edata) => {
    shell.openExternal(edata.url);
    return { action: 'deny' };
  });
  // Remove this if your app does not use auto updates
  // eslint-disable-next-line
  new AppUpdater();
};
        - 应用事件监听: 对应用的一些事件进行监听,如 
window-all-closed事件,当所有窗口关闭时,退出应用(在 macOS 中会保持应用在内存中)。还有app.whenReady()事件,在应用准备好后创建主窗口,并在 macOS 中点击 dock 图标时重新创建窗口。 - 自动更新: 代码中调用了 
electron-updater的autoUpdater来进行自动更新检查。自动更新功能需要结合应用更新服务器,当有新版本可用时,应用会自动下载并应用更新。 
自动更新
自动更新: 代码中调用了 electron-updater 的 autoUpdater 来进行自动更新检查。自动更新功能需要结合应用更新服务器,当有新版本可用时,应用会自动下载并应用更新。
            
            
              js
              
              
            
          
          class AppUpdater {
  constructor() {
    // log.transports.file.level = 'info';
    log.transports.console.format = '{h}:{i}:{s} {text}';
    log.transports.console.level = 'debug'; // 设置日志级别为 debug 或其他级别
    autoUpdater.logger = log;
    autoUpdater.checkForUpdatesAndNotify();
  }
}