在之前的一篇文章 《Electron 打包 Angular 应用》中我介绍了把 angular 项目打包成桌面应用的方法。但是我们实际发布软件给用户安装之后,由于 angular 中都是用 console.log 进行日志输出,假设软件出现了问题,没有日志文件收集回来的话,开发人员也很难去定位错误,因此本文介绍在 electron 打包出来的 angular 应用中,如果输出日志文件。
我们使用的插件是 electron-log: https://github.com/megahertz/electron-log。
1. 安装插件
npm install electron-log
2. 在 electron 主进程文件 el-main.js 文件中使用 electron-log
const { app, BrowserWindow } = require('electron');
const logger = require('electron-log');
logger.transports.file.level = 'info';
logger.transports.file.file = './electron-test.log';
// 保持对window对象的全局引用,如果不这么做的话,当JavaScript对象被
// 垃圾回收的时候,window对象将会自动的关闭
let win
function createWindow() {
...
logger.info('electron test app start at ', new Date());
...
}
...
3. 在 angular 部分(渲染进程)使用 electron-log
需要使用一个额外的依赖项 ngx-electron
npm install ngx-electron
在 app.module.ts 文件中声明依赖:
...
import { NgxElectronModule } from 'ngx-electron';
@NgModule({
declarations: [
AppComponent
],
imports: [
...
NgxElectronModule,
...
],
providers: [
...
],
bootstrap: [AppComponent]
})
export class AppModule { }
在组件中使用 electron-log
...
import { ElectronService } from 'ngx-electron';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
logger: any;
constructor(
...
private electronService: ElectronService
) {
if (this.electronService.isElectronApp) {
this.logger = this.electronService.remote.require('electron-log');
console.log = this.logger.log;
}
console.log('[AppComponent] constructor called');
...
}
}
这段代码中有一句 console.log = this.logger.log; 这行代码意思是将 console.log 赋值为 electron-log 对象,这样这个组件中所有的 console.log 输出的内容也能被记录到日志文件中,当然直接使用 this.logger.log 来替换 console.log 也是可以的。
到目前为止一切看起来很顺利,并且如果这个时候你使用 ng build 之后, 在 dist/electron-test/ 目录下执行 electron . ,你的应用就能正常运行起来,日志文件也能正常产生。但是问题来了,如果你使用 electron-packager 打包出来的 exe 应用,点开时却会报错: Cannot find module electron-log !
产生问题的位置在于 el-main.js 文件中的 const logger = require('electron-log');,这里找不到依赖项,但是为什么直接使用 electron 指令去运行 el-main.js 文件不会出问题 我就不清楚了。
解决这个问题的关键点,在于你需要在编译之后的文件中,把 electron-log 这个组件拷贝到编译输出目录的 node_modules 中。
4. 记得 《Electron 打包 Angular 应用》这篇文章中项目目录 src/package.json 文件吗,我们需要把 项目根目录下 package.json 文件中的 electron-log 依赖项拷贝到 src/package.json 文件中
{
"name": "electron-test",
"version": "1.0.0",
"main": "el-main.js",
"description": "",
"author": "walli",
"dependencies": {
"electron-log": "^3.0.9"
}
}
这一步很重要,因为如那篇文章中所说,这个 src/package.json 文件是 electron 运行的描述文件,同时也是 electron-package 打包时的描述文件,如果缺失了这个依赖描述,最后在打包出去的文件中,是不会包含 electron-log 这个依赖的。
5. 拷贝 electron-log 的依赖文件
修改 angular.json 文件
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"electron-test": {
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/electron-test", // 这行指定了输出目录
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "src/tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets",
"src/el-main.js", // 下面两句就是拷贝需要的文件
"src/package.json",
{
"glob": "**/*",
"input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
"output": "/assets/"
},
{
"glob": "**/*", // 拷贝 electron-log 依赖到输出文件夹中
"input": "./node_modules/electron-log/",
"output": "/node_modules/electron-log/"
}
],
...
},
...
},
...
}
},
...
}
}
所以最后,使用 ng build 产生的目录结构应该类似于以下结构:
|--dist/
|--dist/electron-test/
|--dist/electron-test/assets/
|--dist/electron-test/node_modules/
|--dist/electron-test/node_modules/electron-log/
|--dist/electron-test/node_modules/...
|--dist/electron-test/...
|--dist/electron-test/index.html
|--dist/electron-test/el-main.js
|--dist/electron-test/package.json
electron-packager 打包时,就是将这个 dist/electron-test 下面所有的文件全部拷贝到它的 resource/app 目录下,这样,我们就把 electron-log 的依赖文件拷贝过去了,这时候再去运行 electron-test.exe 文件,就不会再报错了。