diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..b17bc02a --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +os: + - linux + - osx +dist: trusty +sudo: false + +addons: + apt: + packages: + - google-chrome-beta +before_install: + - | + if [ "$TRAVIS_OS_NAME" = "osx" ]; then + brew tap caskroom/versions > /dev/null + brew update > /dev/null + brew cask install google-chrome-beta + fi + +language: node_js +node_js: + - "6" + - "7" \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..ab57eeaf --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,24 @@ +{ + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Launch Program", + "program": "${workspaceRoot}/src/index.ts", + "outFiles": ["${workspaceRoot}/lib/**/*.js"], + "smartStep": true + }, + { + "type": "node", + "request": "attach", + "name": "Attach to Port", + "address": "localhost", + "port": 5858, + "outFiles": [] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index 851f1a2a..9b81411c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # html-pdf-chrome + +[![Travis CI](https://travis-ci.org/westy92/html-pdf-chrome.svg)](https://travis-ci.org/westy92/html-pdf-chrome/) + HTML to PDF converter via Chrome/Chromium diff --git a/lib/src/index.js b/lib/src/index.js index ffe8a29f..058a7501 100644 --- a/lib/src/index.js +++ b/lib/src/index.js @@ -39,10 +39,14 @@ function create(html, options) { reject(err); }); }).then((createResult) => __awaiter(this, void 0, void 0, function* () { - yield chrome.kill(); + if (chrome) { + yield chrome.kill(); + } return createResult; })).catch((err) => __awaiter(this, void 0, void 0, function* () { - yield chrome.kill(); + if (chrome) { + yield chrome.kill(); + } return Promise.reject(err); })); }); diff --git a/lib/src/index.js.map b/lib/src/index.js.map index 6c8363fd..a83fd312 100644 --- a/lib/src/index.js.map +++ b/lib/src/index.js.map @@ -1 +1 @@ -{"version":3,"sources":["src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["'use strict';\n\nimport * as CDP from 'chrome-remote-interface';\nimport * as fs from 'fs';\nimport { ChromeLauncher } from 'lighthouse/lighthouse-cli/chrome-launcher';\nimport { getRandomPort } from 'lighthouse/lighthouse-cli/random-port';\nimport { Readable, Stream } from 'stream';\n\nexport interface Options {\n port?: number;\n}\n\nexport async function create(html: string, options?: Options): Promise {\n const myOptions = Object.assign({}, options);\n myOptions.port = myOptions.port || await getRandomPort();\n const chrome = await launchChrome(myOptions.port);\n return new Promise((resolve, reject) => {\n CDP(myOptions, async (client) => {\n try {\n const {Page} = client;\n await Page.enable(); // Enable Page events\n await Page.navigate({url: `data:text/html,${html}`});\n await Page.loadEventFired();\n // https://chromedevtools.github.io/debugger-protocol-viewer/tot/Page/#method-printToPDF\n const pdf = await Page.printToPDF();\n return resolve(new CreateResult(pdf.data));\n } catch (err) {\n reject(err);\n } finally {\n client.close();\n }\n }).on('error', (err) => {\n reject(err);\n });\n }).then(async (createResult) => {\n await chrome.kill();\n return createResult;\n }).catch(async (err) => {\n await chrome.kill();\n return Promise.reject(err);\n });\n}\n\nasync function launchChrome(port: number) {\n const launcher = new ChromeLauncher({\n port,\n autoSelectChrome: true,\n additionalFlags: [\n '--disable-gpu',\n '--headless',\n ],\n });\n try {\n await launcher.run();\n return launcher;\n } catch (err) {\n await launcher.kill();\n }\n}\n\nexport class CreateResult {\n\n private static async writeFile(filename: string, data: Buffer) {\n return new Promise((resolve, reject) => {\n fs.writeFile(filename, data, (err) => {\n err ? reject(err) : resolve();\n });\n });\n }\n\n /**\n * Base64-encoded PDF data.\n */\n private data: string;\n\n public constructor(data: string) {\n this.data = data;\n }\n\n public toBase64(): string {\n return this.data;\n }\n\n public toBuffer(): Buffer {\n return Buffer.from(this.data, 'base64');\n }\n\n public toStream(): Stream {\n const stream = new Readable();\n stream.push(this.data);\n stream.push(null);\n return stream;\n }\n\n public async toFile(filename: string): Promise {\n await CreateResult.writeFile(filename, this.toBuffer());\n }\n\n}\n"],"sourceRoot":"../.."} \ No newline at end of file +{"version":3,"sources":["src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["'use strict';\n\nimport * as CDP from 'chrome-remote-interface';\nimport * as fs from 'fs';\nimport { ChromeLauncher } from 'lighthouse/lighthouse-cli/chrome-launcher';\nimport { getRandomPort } from 'lighthouse/lighthouse-cli/random-port';\nimport { Readable, Stream } from 'stream';\n\nexport interface Options {\n port?: number;\n}\n\nexport async function create(html: string, options?: Options): Promise {\n const myOptions = Object.assign({}, options);\n myOptions.port = myOptions.port || await getRandomPort();\n const chrome = await launchChrome(myOptions.port);\n return new Promise((resolve, reject) => {\n CDP(myOptions, async (client) => {\n try {\n const {Page} = client;\n await Page.enable(); // Enable Page events\n await Page.navigate({url: `data:text/html,${html}`});\n await Page.loadEventFired();\n // https://chromedevtools.github.io/debugger-protocol-viewer/tot/Page/#method-printToPDF\n const pdf = await Page.printToPDF();\n return resolve(new CreateResult(pdf.data));\n } catch (err) {\n reject(err);\n } finally {\n client.close();\n }\n }).on('error', (err) => {\n reject(err);\n });\n }).then(async (createResult) => {\n if (chrome) {\n await chrome.kill();\n }\n return createResult;\n }).catch(async (err) => {\n if (chrome) {\n await chrome.kill();\n }\n return Promise.reject(err);\n });\n}\n\nasync function launchChrome(port: number) {\n const launcher = new ChromeLauncher({\n port,\n autoSelectChrome: true,\n additionalFlags: [\n '--disable-gpu',\n '--headless',\n ],\n });\n try {\n await launcher.run();\n return launcher;\n } catch (err) {\n await launcher.kill();\n }\n}\n\nexport class CreateResult {\n\n private static async writeFile(filename: string, data: Buffer) {\n return new Promise((resolve, reject) => {\n fs.writeFile(filename, data, (err) => {\n err ? reject(err) : resolve();\n });\n });\n }\n\n /**\n * Base64-encoded PDF data.\n */\n private data: string;\n\n public constructor(data: string) {\n this.data = data;\n }\n\n public toBase64(): string {\n return this.data;\n }\n\n public toBuffer(): Buffer {\n return Buffer.from(this.data, 'base64');\n }\n\n public toStream(): Stream {\n const stream = new Readable();\n stream.push(this.data);\n stream.push(null);\n return stream;\n }\n\n public async toFile(filename: string): Promise {\n await CreateResult.writeFile(filename, this.toBuffer());\n }\n\n}\n"],"sourceRoot":"../.."} \ No newline at end of file diff --git a/package.json b/package.json index d0d03919..bf49707f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "license": "MIT", "typings": "lib/src/index.d.ts", "engines": { - "node": ">= 4.5.0" + "node": ">= 6" }, "os": [ "darwin", diff --git a/src/index.ts b/src/index.ts index e294661b..f29b5c91 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,10 +33,14 @@ export async function create(html: string, options?: Options): Promise { - await chrome.kill(); + if (chrome) { + await chrome.kill(); + } return createResult; }).catch(async (err) => { - await chrome.kill(); + if (chrome) { + await chrome.kill(); + } return Promise.reject(err); }); }