Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)

背景

最近新项目的需求是开发桌面应用,因此需要引入Electron。而桌面应用与浏览器web服务的主要区别就在于代码是不是在浏览器中跑的。所以我们仍然沿用web开发时的主流开发框架angular。

于是,新项目前端技术为electron + angular。

Electron + angular初始化

首先,非常重要的一点是:node版本必须高于18.16.1,因为低于这个版本的node无法支持electron。

然后,先初始化一个angular项目(初始化后如图,这个不再赘述)。
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第1张图片

接着,我们需要安装electron,在angular项目的根目录下执行

ELECTRON_MIRROR=http://npm.taobao.org/mirrors/electron/ npm install --save-dev electron 

安装成功后可以看到package.json里有了electron的依赖:
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第2张图片

为了给我们的angular项目套上electron,我们还需要去重新设置一下入口文件:
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第3张图片

然后在根目录下新建main.js,按照electron的方式配置启动路径,指向angular项目。

// 根目录下的main.js文件
const {app, BrowserWindow} = require('electron');
const url = require('url');
const path = require('path');

function onReady () {
  win = new BrowserWindow({width: 1600, height: 1000})
  loadUrl();

  // 打开开发者工具
  win.webContents.openDevTools()

  // 当 window 被关闭,这个事件会被触发。
  win.on('closed', () => {
    // 取消引用 window 对象,如果你的应用支持多窗口的话,
    // 通常会把多个 window 对象存放在一个数组里面,
    // 与此同时,你应该删除相应的元素。
    win = null
  })
}

function loadUrl() {
  win.loadURL(url.format({
    pathname: path.join(
      __dirname,
      'dist/angular-electron-app/index.html'),
    protocol: 'file:',
    slashes: true
  }))
}

//在ready事件里
app.on('ready', async () => {
  onReady();
})


// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在macOS上,当单击dock图标并且没有其他窗口打开时,
  // 通常在应用程序中重新创建一个窗口。
  if (win === null) {
    onReady()
  }
})

去到src/index.html,将

改为

最后在脚本中加入启动命令:
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第4张图片

根目录下终端运行命令

npm run electron

即可启动成功:
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第5张图片

配置快捷键调起控制台

electron窗口毕竟不是浏览器,该窗口中的控制台是由main.js中的 openDevTools()方法控制的,前文的main.js中配置了在窗口打开时控制台打开。如果在开发过程中不小心把控制台给关了,是无法通过在electron窗口中的操作调起控制台的。想要再打开就只能去到终端ctrl + c后再执行一次electron启动命令。

搞开发的都知道,没有控制台的开发就像断了一条腿一样难受。

所以我们还需要对控制台的快捷调起进行一番配置。

electron框架提供的与计算机交互的接口中有一个 globalShortcut,官方对它的描述是:
Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载)_第6张图片

globalShortcut 可以检测键盘事件,还可以向操作系统注册/注销全局快捷键。有了它,我们就可以实现我们想要的功能了。

首先在main.js中,引入 globalShortcut

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

然后将

//在ready事件里
app.on('ready', async () => {
  onReady();
})

换成

//在ready事件里
app.on('ready', async () => {
  // Ctrl + Shift + i 快捷键调起/关闭控制台
  globalShortcut.register('CommandOrControl+Shift+i', function () {
    // 判断现在控制台是否处于打开状态
    if (win.webContents.isDevToolsOpened()) {
      // 如果被打开,则关闭
      win.webContents.closeDevTools()
    } else {
      // 如果没有被打开,则调起
      win.webContents.openDevTools()
    }
  })
  onReady();
})

这里使用的是Ctrl + Shift + i 快捷键调起控制台,当然也可以换成别的。

配置热加载

熟悉angular的朋友们都知道,angular的一个很人性化的点就是热加载,当代码有所变动时浏览器中会自动检测到并刷新,而不用手动刷新。因此,使用angular从web开发转为桌面程序开发时自然也是希望开发中保持这个特点。所以还需要配置一下热加载。

我们先回顾一下前文配置:

// main.js中配置的指向angular项目的启动路径
function loadUrl() {
  win.loadURL(url.format({
    pathname: path.join(
      __dirname,
      'dist/angular-electron-app/index.html'),
    protocol: 'file:',
    slashes: true
  }))
}

由于指向的路径是ng build后的dist文件夹下的angular项目,所以这样自然是无法实现热加载的,因为我们不可能改一点代码就ng build一次,这不现实。

网上查到的资料来看,大多数的做法及原理都很简单,将electron加载路径由dist/下的angular项目改为 http://localhost:4200,即将上述配置改为:

function loadUrl() {
  win.loadURL('http://localhost:4200');
}

然后在启动electron窗口之前先启动angular,即在一个终端中先 ng s,再在另一个终端中 npm run electron

这样做的确可以实现electron窗口中angular项目的热加载。

但存在一个很重要且必须要注意的问题,就是electron打包时不能就这样打包。如果就这样打包发给用户的话,用户双击启动后只会看到一个空白的窗口,因为angular服务并没有启动但electron却加载了angular服务的端口。所以打包时加载路径仍然应该配置dist/下的angular项目。

还有一点,居然要开两个终端,执行两条启动命令,总觉得很不爽。

综上所述,开发时为了便利,我们可以加载路径指向 http://localhost:4200 以实现热加载;而打包时加载路径仍然应该配置dist/下的angular项目

完整main.js

const {app, BrowserWindow, globalShortcut} = require('electron');
const url = require('url');
const path = require('path');

function onReady () {
  win = new BrowserWindow({width: 1600, height: 1000})
  // 打包时成APP时用此路径
  // loadUrlWhenPackage();

  // 开发时为了实现angular热加载,用此路径
  // 打开终端先ng serve启动angular服务
  // 打开另一个终端npm run electron启动窗口服务
  // 此时可实现热加载
  loadUrlWhenDevelop();

  // 打开开发者工具
  win.webContents.openDevTools()

  // 当 window 被关闭,这个事件会被触发。
  win.on('closed', () => {
    // 取消引用 window 对象,如果你的应用支持多窗口的话,
    // 通常会把多个 window 对象存放在一个数组里面,
    // 与此同时,你应该删除相应的元素。
    win = null
  })
}

// 打包时使用的路径
function loadUrlWhenPackage() {
  win.loadURL(url.format({
    pathname: path.join(
      __dirname,
      'dist/line-data-record/index.html'),
    protocol: 'file:',
    slashes: true
  }))
}

// 开发时使用的路径(实验angular热加载)
function loadUrlWhenDevelop() {
  win.loadURL('http://localhost:4200');
}

//在ready事件里
app.on('ready', async () => {
  // Ctrl + Shift + i 快捷键调起/关闭控制台
  globalShortcut.register('CommandOrControl+Shift+i', function () {
    if (win.webContents.isDevToolsOpened()) {
      win.webContents.closeDevTools()
    } else {
      win.webContents.openDevTools()
    }
  })
  onReady();
})


// 当全部窗口关闭时退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非用户用 Cmd + Q 确定地退出,
  // 否则绝大部分应用及其菜单栏会保持激活。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在macOS上,当单击dock图标并且没有其他窗口打开时,
  // 通常在应用程序中重新创建一个窗口。
  if (win === null) {
    onReady()
  }
})

参考资料

https://www.logicflow.ai/blog/angular-desktop-applications-wi...

https://zhuanlan.zhihu.com/p/298530109

https://blog.csdn.net/qq_40282732/article/details/...

你可能感兴趣的:(Electron + angular 项目初始化(配置快捷键调起控制台 + 热加载))