Skip to content

Commit bcb4436

Browse files
committed
Added more options to control and debug the headless browser. Can now override logging.
1 parent ffa45a2 commit bcb4436

File tree

6 files changed

+168
-41
lines changed

6 files changed

+168
-41
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "capture-template",
3-
"version": "1.0.8",
3+
"version": "1.0.9",
44
"description": "This library is responsible for expanding a template web page and then capturing it PNG or PDF.",
55
"main": "build/index.js",
66
"types": "build/index.d.ts",

src/index.ts

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,67 @@ import * as fs from 'fs-extra';
44
import * as path from 'path';
55
const promisify = require('promisify-any');
66

7+
/**
8+
* Allows caller to override logging.
9+
*/
10+
export interface ILog {
11+
/**
12+
* Log an info message.
13+
*/
14+
info(msg: string): void;
15+
16+
/**
17+
* Log a warning message.
18+
*/
19+
warn(msg: string): void;
20+
21+
/**
22+
* Log an error message.
23+
*/
24+
error(msg: string): void;
25+
}
26+
27+
/**
28+
* Specifies options that can be passed to the capture function.
29+
*/
30+
export interface ICaptureOptions {
31+
32+
/**
33+
* Optionally override logging.
34+
*/
35+
log?: ILog;
36+
37+
/**
38+
* Optional timeout for Electron's wait function.
39+
*/
40+
waitTimeout?: number;
41+
42+
/**
43+
* Optional timeout for Electron's goto function.
44+
*/
45+
gotoTimeout?: number;
46+
47+
/**
48+
* Opens Electron's devtools, this only helps if show browser is also enabled!
49+
*/
50+
openDevTools?: boolean;
51+
52+
/**
53+
* Set to true to show the headless browser.
54+
*/
55+
showBrowser?: boolean;
56+
57+
/**
58+
* Specify the path to Electron if that's necessary for you.
59+
*/
60+
electronPath?: string;
61+
}
62+
763
//
864
// Initalise the template renderer.
965
//
10-
async function initTemplateRenderer(data: any, templatePath: string, port: number, electronPath?: string): Promise<ITemplateRenderer> {
11-
const templateRenderer = new TemplateRenderer(electronPath);
66+
async function initTemplateRenderer(data: any, templatePath: string, port: number, options?: ICaptureOptions): Promise<ITemplateRenderer> {
67+
const templateRenderer = new TemplateRenderer(options);
1268
await templateRenderer.start();
1369
await templateRenderer.loadTemplate(data, templatePath, port);
1470
return templateRenderer;
@@ -25,21 +81,21 @@ async function deinitTemplateRenderer(templateRenderer: ITemplateRenderer): Prom
2581
//
2682
// Expand a template web page and capture it to an image file.
2783
//
28-
export async function captureImage(data: any, templatePath: string, outputPath: string, electronPath?: string): Promise<void> {
84+
export async function captureImage(data: any, templatePath: string, outputPath: string, options?: ICaptureOptions): Promise<void> {
2985
await fs.ensureDir(path.dirname(outputPath));
3086
const autoAssignPortNo = 0; // Use port no 0, to automatically assign a port number.
31-
const templateRenderer = await initTemplateRenderer(data, templatePath, autoAssignPortNo, electronPath);
87+
const templateRenderer = await initTemplateRenderer(data, templatePath, autoAssignPortNo, options);
3288
await templateRenderer.renderImage(outputPath);
3389
await deinitTemplateRenderer(templateRenderer);
3490
}
3591

3692
//
3793
// Expand a template web page and capture it to a PDF file.
3894
//
39-
export async function capturePDF(data: any, templatePath: string, outputPath: string, electronPath?: string): Promise<void> {
95+
export async function capturePDF(data: any, templatePath: string, outputPath: string, options?: ICaptureOptions): Promise<void> {
4096
await fs.ensureDir(path.dirname(outputPath));
4197
const autoAssignPortNo = 0; // Use port no 0, to automatically assign a port number.
42-
const templateRenderer = await initTemplateRenderer(data, templatePath, autoAssignPortNo, electronPath);
98+
const templateRenderer = await initTemplateRenderer(data, templatePath, autoAssignPortNo, options);
4399
await templateRenderer.renderPDF(outputPath);
44100
await deinitTemplateRenderer(templateRenderer);
45101
}

src/template-renderer.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { IWebPageRenderer, WebPageRenderer } from "./web-page-renderer";
22
import { ITemplateWebServer, TemplateWebServer } from "./template-web-server";
3+
import { ICaptureOptions } from "./index";
34

45
declare const document: any;
56

@@ -56,9 +57,9 @@ export interface ITemplateRenderer {
5657
export class TemplateRenderer implements ITemplateRenderer {
5758

5859
/**
59-
* Specifies the path to load Electron from or null to use default path.
60+
* Options for capturing.
6061
*/
61-
electronPath?: string;
62+
private options?: ICaptureOptions;
6263

6364
/**
6465
* Renders the web page.
@@ -70,8 +71,8 @@ export class TemplateRenderer implements ITemplateRenderer {
7071
*/
7172
private templateWebServer: ITemplateWebServer | null = null;
7273

73-
constructor (electronPath?: string) {
74-
this.electronPath = electronPath;
74+
constructor (options?: ICaptureOptions) {
75+
this.options = options;
7576
}
7677

7778
/**
@@ -86,7 +87,7 @@ export class TemplateRenderer implements ITemplateRenderer {
8687
* For performance reasons the template render can be reused to render multiple web pages.
8788
*/
8889
async start (): Promise<void> {
89-
this.webPageRenderer = new WebPageRenderer(this.electronPath);
90+
this.webPageRenderer = new WebPageRenderer(this.options);
9091
await this.webPageRenderer.start();
9192
}
9293

@@ -110,7 +111,7 @@ export class TemplateRenderer implements ITemplateRenderer {
110111
async loadTemplate(data: any, templatePath: string, port: number): Promise<void> {
111112
this.unloadTemplate();
112113

113-
this.templateWebServer = new TemplateWebServer();
114+
this.templateWebServer = new TemplateWebServer(this.options && this.options.log);
114115
await this.templateWebServer.start(data, templatePath, port);
115116
}
116117

src/template-web-server.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { WebServer, IWebServer } from "./web-server";
22
import { inflateTemplate } from "inflate-template";
33
import * as fs from 'fs-extra';
44
import * as path from 'path';
5+
import { ILog } from "./index";
56
const promisify = require('promisify-any');
67

78
declare const document: any;
@@ -39,15 +40,24 @@ export interface ITemplateWebServer {
3940
*/
4041
export class TemplateWebServer implements ITemplateWebServer {
4142

43+
/**
44+
* Optinally override logging.
45+
*/
46+
private log?: ILog;
47+
4248
/**
4349
* For performance reasons this can be reused to instantiate and render multiple web pages.
4450
*/
45-
webServer: IWebServer | null = null;
51+
private webServer: IWebServer | null = null;
4652

4753
/**
4854
* Template configuration, once web server is started and template has been inflated.
4955
*/
50-
templateConfig: any | null = null;
56+
private templateConfig: any | null = null;
57+
58+
constructor(log?: ILog) {
59+
this.log = log;
60+
}
5161

5262
/**
5363
* Get the URL to access the web-sever.

src/web-page-renderer.ts

Lines changed: 60 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { ICaptureOptions } from "./index";
2+
13
const Nightmare = require("nightmare");
24

35
declare const document: any;
@@ -52,17 +54,53 @@ export interface IWebPageRenderer {
5254
export class WebPageRenderer implements IWebPageRenderer {
5355

5456
/**
55-
* Specifies the path to load Electron from or null to use default path.
57+
* Options for capturing.
5658
*/
57-
electronPath?: string;
59+
private options?: ICaptureOptions;
5860

5961
/**
6062
* Nightmare headless browser instance.
6163
*/
62-
nightmare: any | null = null;
64+
private nightmare: any | null = null;
65+
66+
constructor (options?: ICaptureOptions) {
67+
this.options = options;
68+
}
69+
70+
/**
71+
* Log an info message.
72+
*/
73+
info(msg: string): void {
74+
if (this.options && this.options.log) {
75+
this.options.log.info(msg);
76+
}
77+
else {
78+
console.info(msg);
79+
}
80+
}
6381

64-
constructor (electronPath?: string) {
65-
this.electronPath = electronPath;
82+
/**
83+
* Log a warning message.
84+
*/
85+
warn(msg: string): void {
86+
if (this.options && this.options.log) {
87+
this.options.log.warn(msg);
88+
}
89+
else {
90+
console.warn(msg);
91+
}
92+
}
93+
94+
/**
95+
* Log an error message.
96+
*/
97+
error(msg: string): void {
98+
if (this.options && this.options.log) {
99+
this.options.log.error(msg);
100+
}
101+
else {
102+
console.error(msg);
103+
}
66104
}
67105

68106
/**
@@ -71,15 +109,18 @@ export class WebPageRenderer implements IWebPageRenderer {
71109
*/
72110
async start (): Promise<void> {
73111
const nightmareOptions: any = {
74-
show: false,
112+
show: this.options && this.options.showBrowser,
75113
frame: false,
76114
maxHeight: 1000000,
77115
maxWidth: 1000000,
116+
waitTimeout: this.options && this.options.waitTimeout,
117+
gotoTimeout: this.options && this.options.gotoTimeout,
118+
openDevTools: this.options && this.options.openDevTools,
78119
};
79120

80-
if (this.electronPath) {
121+
if (this.options && this.options.electronPath) {
81122
// Include Electron path if specified.
82-
nightmareOptions.electronPath = this.electronPath;
123+
nightmareOptions.electronPath = this.options.electronPath;
83124
}
84125

85126
this.nightmare = new Nightmare(nightmareOptions);
@@ -90,34 +131,34 @@ export class WebPageRenderer implements IWebPageRenderer {
90131

91132
this.nightmare.on('page', (type: string, message: string, stack: any) => {
92133
if (type === "error") {
93-
console.error("Browser page error: " + message);
94-
console.error(stack);
134+
this.error("Browser page error: " + message);
135+
this.error(stack);
95136
}
96137
});
97138

98139
this.nightmare.on("did-fail-load", (event: any, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
99-
console.error("Browser page failed to load.");
100-
console.error("Error code: " + errorCode);
101-
console.error("Error description: " + errorDescription);
102-
console.error("Validated URL: " + validatedURL);
103-
console.error("Is main frame: " + isMainFrame);
140+
this.error("Browser page failed to load.");
141+
this.error("Error code: " + errorCode);
142+
this.error("Error description: " + errorDescription);
143+
this.error("Validated URL: " + validatedURL);
144+
this.error("Is main frame: " + isMainFrame);
104145
});
105146

106147
this.nightmare.on('console', (type: string, message: string) => {
107148

108149
if (type === 'log') {
109-
console.log('LOG: ' + message);
150+
this.info('LOG: ' + message);
110151
return;
111152
}
112153

113154
if (type === 'warn') {
114-
console.warn('LOG: ' + message);
155+
this.warn('LOG: ' + message);
115156
return;
116157
}
117158

118159
if (type === 'error') {
119-
console.error("Browser JavaScript error:");
120-
console.error(message);
160+
this.error("Browser JavaScript error:");
161+
this.error(message);
121162
}
122163
});
123164
}

src/web-server.ts

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as express from "express";
22
import * as http from 'http';
33
import * as path from "path";
44
import { ITemplate } from 'inflate-template';
5+
import { ILog } from "./index";
56

67
/**
78
* Web-server component. Serves the chart interative chart.
@@ -29,30 +30,48 @@ export interface IWebServer {
2930
*/
3031
export class WebServer implements IWebServer {
3132

33+
/**
34+
* Optinally override logging.
35+
*/
36+
private log?: ILog;
37+
3238
/**
3339
* The requested port number for the web server.
3440
*/
35-
requestedPortNo: number;
41+
private requestedPortNo: number;
3642

3743
/**
3844
* The assigned port number for the web server.
3945
*/
40-
assignedPortNo: number;
46+
private assignedPortNo: number;
4147

4248
/**
4349
* The Express server instance that implements the web-server.
4450
*/
45-
server: any | null = null;
51+
private server: any | null = null;
4652

4753
/**
4854
* The data that defines the chart.
4955
* Passed to the browser-based chart via REST API.
5056
*/
51-
chartDef: any = {};
57+
private chartDef: any = {};
5258

53-
constructor (portNo: number) {
59+
constructor (portNo: number, log?: ILog) {
5460
this.requestedPortNo = portNo;
5561
this.assignedPortNo = portNo;
62+
this.log = log;
63+
}
64+
65+
/**
66+
* Log an error message.
67+
*/
68+
error(msg: string): void {
69+
if (this.log) {
70+
this.log.error(msg);
71+
}
72+
else {
73+
console.error(msg);
74+
}
5675
}
5776

5877
/**
@@ -100,8 +119,8 @@ export class WebServer implements IWebServer {
100119
response.send(fileContent);
101120
}
102121
catch (err) {
103-
console.error("Error loading template file.");
104-
console.error(err && err.stack || err);
122+
this.error("Error loading template file.");
123+
this.error(err && err.stack || err);
105124

106125
response.sendStatus(404);
107126
}

0 commit comments

Comments
 (0)