这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战
1.问题场景/应用场景
首先第一个,为什么electron集成NestJs。
这样做最主要的目的是:
- 第一个避免通过electron主进程或通过渲染进程,开放其自身的node能力去进行文件啥的操作。
- 第二一个就是使得基于electron开发的这个应用可以做正向或者反向代理。
- 第三一个就是NestJS集成到electron,这样electron自身就是完全的一个套壳,写ui,内置的数据库操作啥的都交给NestJS来操作,通过NestJS,electron中实现文件上传,下载等功能将更为方便。
2. NestJs集成操作
这里的集成操作,ui界面是基于Umijs
的,其他的前端UI界面的集成方式大同小异,本文均具有参考价值
2.1 UmiJs下配置electron
这里我没有采用Umi的第三方关于Electron的集成插件,而是使用的自己的配置方案
- 首先按Umijs的文档创建一个项目,
test
- 安装electron相关依赖包
electron electron-builder electron-reloader
安装在devDependencies
下. - 创建一个
desk.ts
和一个tsconfig.main.json
用于开发electron主进程相关逻辑
desk.ts
基本内容如下
import { BrowserWindow, app } from 'electron';
import path from 'path';
import child_process from 'child_process';
const exec = child_process.exec;
let openExec;
type MyWindow =
| (BrowserWindow & {
rootPath?: string;
dirPath?: string;
})
| null
| BrowserWindow;
let window: MyWindow;
const initWindow = {
width: 1050,
height: 700,
};
const isDevelopment = process.env.NODE_ENV !== 'production';
function createWindow() {
console.log(__dirname);
window = new BrowserWindow({
...initWindow,
webPreferences: {
javascript: true,
plugins: true,
webSecurity: false,
contextIsolation: false,
nodeIntegration: true,
preload: path.join(__dirname, './preload.js'),
},
frame: false,
transparent: true,
});
if (isDevelopment) {
try {
require('electron-reloader')(module, {});
} catch (_) {}
window.webContents.openDevTools();
window.loadURL('http://localhost:8001/');
} else {
window.loadURL('app://./index.html');
}
return window;
}
let serverApp;
app.on('ready', () => {
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true'; //关闭web安全警告
createWindow();
});
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
if (!openExec) {
} else {
exec('taskkill /f /t /im node.exe', function (error, stdout, stderr) {
if (error) {
console.log(error.stack);
console.log('Error code: ' + error.code);
return;
}
console.log('使用exec方法输出: ' + stdout);
console.log(`stderr: ${stderr}`);
});
}
}
});
从上面代码可以看到有这样一段代码 preload: path.join(__dirname, './preload.js')
,这是很关键的,因为umijs,渲染进程中没法直接使用electron提供的能力,需要用这样一个文件进行预加载,因此在desk.ts
同级下创建preload.ts
文件
import electron, { ipcRenderer } from 'electron';
global.electron = electron;
(window as any).ipcRenderer = ipcRenderer;
其主要作用就是把electron能力挂载到window对象属性上,做全局属性或方法
然后就是修改一下项目启动命令在package.json
中
...
"start:main": "tsc -w --p tsconfig.main.json",
"start:electron": "electron ./dist/desk.js",
"build:electron": "electron-builder --win",
"start:umi": "umi dev",
"build:umi": "umi build",
// electron 打包配置
"build": {
"extraResources": {
"from": "./resources/",
"to": ""
},
"productName": "test",
"appId": "test",
"win": {
"icon": "./resources/icon.ico",
"target": [
"nsis",
"zip"
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowElevation": true,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true,
"shortcutName": "icon",
"installerIcon": "./resources/icon.ico",
"uninstallerIcon": "./resources/icon.ico",
"installerHeaderIcon": "./resources/icon.ico"
}
},
2.2 集成NestJs
- 安装Nestjs相关依赖包,请注意,这里骚操作就来了
- Nestjs相关的依赖包是安装在
dependencies
,umijs的包全部转移到devDependencies
- 原因的话就是Nestjs打包出来并不会吧node_moudules模块加载进去,所以需要通过这样的配置,在打包electron的时候,将这些依赖打进去
- Nestjs相关的依赖包是安装在
- 在项目根目录下创建一个server文件夹,然后就是
tsconfig.build.json
,修改package.json
"start:nest": "nest start --watch",
"build:nest": "nest build",
tsconfig.build.json
这个文件很重要,这个是运行yarn start:nest
命令所识别的tsconfig
{
"exclude": [
"node_modules",
"test",
"dist",
"server/dist",
"./src",
"deskapp",
"mock",
"**/*spec.ts"
],
"compilerOptions": {
"strict": false,
"module": "commonjs",
"declaration": true,
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2017",
"sourceMap": true,
"outDir": "./server/dist",
"baseUrl": "./server",
"incremental": true,
"skipLibCheck": true,
"strictNullChecks": false,
"noImplicitAny": false,
"strictBindCallApply": false,
"forceConsistentCasingInFileNames": false,
"noFallthroughCasesInSwitch": false
}
}
- 创建
nest-cli.json
,修改命令的基本路径指向,在本示例中代码如下:
{
"collection": "@nestjs/schematics",
"sourceRoot": "./server/src"
}
这样一个基本的基于electron 集成nestjs能力的项目就完成了
注备一个大坑
如果electron集成了nestjs,nestjs要进行文件读写操作的话,就不能开启asar
,在打包build的时候,缺点就是暴露了源码...,目前还没找到一个比较合适的方式处理该问题,探索中,后面进一步补充
- (2022-02-07)关于asar,还是选择开启,不然包太大,东西太多,然后在
asarUnpack
当中选择不进行压缩的文件
详情示例项目欢迎参考本人个人项目