@journeyapps-solutions/rocket-pdf

1.2.4 • Public • Published

solutions-rocketPDF

Improved Creation of Handlebar PDF Documents.

The aim of PDF Rocket is to enable a engineer faster and more stable PDF document creation.

The main part of this is the cc-pdf-sass framework that creates consistent PDF styling as well as CC Sass compilation. This enables the use of variable.sass files instead of one massif style.css file.

The Second part, just as important, is an easy way to receive data from the Journey Backend. We do this with cc-util-data, creating a simplistic fast way of retrieving data from the backend. See the readme at https://github.com/journeyapps-solutions/cc-util-data

Lastly is to add a way of easily using all of this, this is why this module exists. By using simple commands, the majority of the work can be completed with data on the local machine.

Documentation

View Styling docs @ https://journeyapps-solutions.github.io/cc-pdf-sass/

Installation

Per machine

yarn global add @journeyapps-solutions/rocket-pdf --save

or

npm install @journeyapps-solutions/rocket-pdf -g

Note, if you are having issues related to the package not being found after install. Double check that the yarn bin or npm bin is added to your path environmental variables

  • run yarn global bin to get the yarn path to use.
  • run npm bin to get the npm bin path.

Deploying

yarn version

Usage

To see the latest list of commands, run

rocketPDF --help

Commands:

  • rocketPDF init
  • rocketPDF compile
  • rocketPDF serve
  • rocketPDF template
  • rocketPDF image encode
  • rocketPDF file down
  • rocketPDF file up
  • rocketPDF file up
  • rocketPDF smoegel init
  • rocketPDF smoegel add

Initializing

I added this section as I think that it is important to understand what happens when running this command rocketPDF init. During this process, the following happens:

  • The index.html gets created or a prompt to override appears
  • The index.js gets created or a prompt to override appears
  • The latest versions of the dependencies are retrieved and set in package.json
  • devDependencies and babel config is added
  • The Sass files variables.scss and custom.scss are created.

This whole process allows rocketPDF to have the correct construct. It is recommended to follow the way the template is laid out.

Local Development

You are able to run rocketPDF locally, with data, as long as you abide to the layout required to do so. You just run rocketPDF serve. RocketPDF requires a couple of things to be able to run the locally:

  • DB credentials added to the .rocketPDF file, this is automated and will be asked when running rocketPDF serve
  • generateData function in the index.js file that gives back an json object with all the data required for the PDF
/**
 * Generate the data required for the template
 * N.B. This function is used in local running of PDF Rocket
 * @param  {string} objectID ID of the object being referenced
 * @return {object}          [description]
 */
export async function generateData(event) {
  const _ccUtilData = new ccUtilData(this.backend);

  let objectID;

  if(this.source == CloudCode.EDITOR_TEST && CloudCode.task.env == 'testing') {
    objectID = ''; // TODO implement test case
  } else {
    objectID = event.object.id; //TODO implement correct ID
  }

  //Declare all the data objects needed to pull through to the PDF
  let _data = {};

  //TODO Fetch Data

  return _data;
}
  • generateHTML function that is responsible to take the data and output the raw html
/**
 * Generate the document via handlebars
 * N.B. This function is used in local running of PDF Rocket
 * @param  {[type]} data [description]
 * @return {[type]}      [description]
 */
export async function generateHTML(data) {

  // Compile the variable.sass and custom.sass in runtime
  const _compiledSass = await ccPdfSass.compileSass(__dirname);

  // Add css to JSON payload
  data.css = _compiledSass;

  //Get the CSS and HTML Files
  const _html = fs.readFileSync(`${__dirname}/index.html`, 'utf8');

  // Generate HTML using handlebars
  const _pdfTemplate = handlebars.compile(_html);
  const _pdfHtml = _pdfTemplate(data);

  return _pdfHtml;
}

Debugging rocketPDF serve

It is possible to step through and debug the code executed in the generateHTML and generateData functions. The NodeJS developer tools are now exposed when running rocketPDF serve. There are multiple methods of interacting with the NodeJS developer tools. Only a few are mentioned below.

VS Code

There are multiple methods in VS Code to access the debug server. See the guide on debugging in VS Code.

The simplest method is to open a Javascript debugging terminal. This can be achieved by selecting Debug: JavaScript Debug Terminal from the command pallet. Inset breakpoints or debugger statements in the generateHTML or generateData functions in index.js. Run rocketPDF serve from the VS Code terminal and observe that the IDE will gain access once the functions are triggered.

Node Inspect

Other tools such as Chrome Dev tools or the node-inspect npm package can connect to the exposed websocket. To expose a websocket run rocketPDF serve --inspect from any terminal. Copy the debug url into your tool of choice. The code will continue once a debug client has connected.

Quick Start

  1. Create a new Cloud Code task (example: test_rocketPDF)
  2. Open the terminal and enter rocketPDF file down and follow the instructions.
  3. Enter rocketPDF init. This will initialize the project with the latest dependencies.
  4. Enter rocketPDF serve to preview the pdf.
  5. While the above command is still running, update the heading in the index.html file. Save changes. Changes will auto reflect in preview.
  6. Open variable.sass and update the color variable $white: #fff; to $white: red;. Save changes and check preview.
  7. Cancel current running serve by entering CTR + C.
  8. Enter rocketPDF file up to upload your files to the new Cloud Code task
  9. Copy the .npmrc credentials over to your task.
  10. Setup the config.js file for the task.
  11. Run task to make sure everything compiles.

Example of use @ https://build-preprod.journeyapps.com/apps/5989b1c1c93305497aa71453-hello-world#/cloudcode/edit/example/index.js:

const config = require('./config');

const fs = require('fs');
const assert = require('assert');
const Rollbar = require('rollbar');
const handlebars = require('handlebars');

const pdf = require('@journeyapps/pdf-reports');
const ccPdfSass = require('@journeyapps-solutions/cc-pdf-sass');
const ccUtilData = require('@journeyapps/cc-util-data');

export async function run(event) {

  const rollbar = new Rollbar({
    accessToken: config.rollbar,
    captureUncaught: true,
    captureUnhandledRejections: true,
    environment: CloudCode.task.env
  });

  //Setup Rollbar for cloud code events (excluding editor)
  if(this.source !== CloudCode.EDITOR_TEST) {
    this.on('beforeTimeout', () => {
      rollbar.critical(`${CloudCode.task.name} - Script timeout imminent!`, { custom: { context: this, event } });
    });
    this.on('highMemory', () => {
      rollbar.critical(`${CloudCode.task.name} - High memory usage!`, { custom: { context: this, event, memory: process.memoryUsage() } });
    });
  }

  console.log("Event", JSON.stringify(event));

  try {

    let _data = await generateData.call(this, event);
    let _pdfHtml = await generateHTML.call(this, _data);

    // Setup authentication for PDF service
    // This token is short-lived, so it must be set again on every run.
    pdf.setApiToken(this.backend.token);

    // Covert the HTML to PDF
    const _generatedPdf = await pdf.generatePdf({
      html: _pdfHtml
    });

    let _attachment = await _generatedPdf.toEmailAttachment(`${CloudCode.task.name}.pdf`);

    await sendMail(_attachment);

  } catch(error) {

    if(this.source !== CloudCode.EDITOR_TEST) {
      rollbar.error("Cloud Code - " + CloudCode.task.name + " - Unexpected Error", JSON.stringify({
        error: error
      }));
    }

    throw error;
  }
}

/**
 * Generate the data required for the template
 * N.B. This function is used in local running of PDF Rocket
 * @param  {string} objectID ID of the object being referenced
 * @return {object}          [description]
 */
export async function generateData(event) {
  const _ccUtilData = new ccUtilData(this.backend);

  let objectID;

  if(this.source == CloudCode.EDITOR_TEST && CloudCode.task.env == 'testing') {
    let _booking = await DB.booking.first();
    objectID = _booking.id; // TODO implement test case
  } else {
    objectID = event.object.id; //TODO implement correct ID
  }

  //Declare all the data objects needed to pull through to the PDF
  const _dataJson = await _ccUtilData.fetchData(objectID, 'booking', ['room','room.hotel']);

  //TODO Fetch Data

  return _dataJson;
}

/**
 * Generate the document via handlebars
 * N.B. This function is used in local running of PDF Rocket
 * @param  {[type]} data [description]
 * @return {[type]}      [description]
 */
export async function generateHTML(data) {

  // Compile the variable.sass and custom.sass in runtime
  const _compiledSass = await ccPdfSass.compileSass(__dirname);

  // Add css to JSON payload
  data.css = _compiledSass;

  //Get the CSS and HTML Files
  const _html = fs.readFileSync(`${__dirname}/index.html`, 'utf8');

  // Generate HTML using handlebars
  const _pdfTemplate = handlebars.compile(_html);
  const _pdfHtml = _pdfTemplate(data);

  return _pdfHtml;
}

async function sendMail(attachment) {

  const _email = {
    from: 'johndoe@journeyapps.com',
    to: 'johndoe@journeyapps.com',
    subject: "Test email",
    text: "Please find attached the generated mail",
    attachments: [attachment]
  };

  // Create mailer instance for sending of mail.
  const _mailer = new ccSendGrid({}, config.sendGrid, CloudCode.task.env, config.whiteList);

  await _mailer.send(_email);
}

Smoegel

yes, smoegel seems to be a real term. anyways. The smoegel actions enables creating of mock pdf's a lot faster and easier. The whole process is basicly automated, from creation to upload to the CC task.

Getting started

  1. Create an Cloud Code task in your app. Example smoegel
  2. Create an new directory we are going to work in. This can be anywhere.
  3. Open your terminal and navigate to this new directory
  4. Run rocketPDF smoegel init initializing the smoegel. Follow the questions as the are prompt.
  5. View the current set of code in your Cloud Code task in the platform editor. Things should look different.
  6. Lets add some resources (image/pdf) by running rocketPDF smoegel add and following the prompts.
  7. If you want to upload your code (That is you said no too the prompt), then run rocketPDF file up
  8. Copy the .npmrc credentials over to your task. This allows Cloud Code to access the solutions modules.
  9. Click run, this should generate a PDF with your image and/or attachments added.
  10. Setup the config.js file for the task.
  11. Run task to make sure everything compiles.
  12. Now that the basics are setup, you can start editing the Cloud Code task, however, remember that any changes made in the Cloud Code task can be overwritten if you upload work locally, so to keep things in sync, run rocketPDF file down

Smoegel More info - Static PDF's

In your index.js you will find the EXTRA_ATTACHMENTS field. This is where all static documents get reference to be used in the task.

/**
 * List of Extra static pdf attachments to load
 */
const EXTRA_ATTACHMENTS = [
];

Attachments added to the above field, will be read by the below code. Here you can change the logic of which PDF's are added.

let _attachments = [];
let _generatedPdfAttachment = await _generatedPdf.toEmailAttachment(`${CloudCode.task.name}.pdf`);
_attachments.push(_generatedPdfAttachment);

for (let i in EXTRA_ATTACHMENTS) {
  let _extraAttachment = await fs.readFile(`${process.cwd()}/${EXTRA_ATTACHMENTS[i]}`);
  _attachments.push({
    filename: EXTRA_ATTACHMENTS[i],
    type: 'application/pdf',
    content: _extraAttachment.toString('base64')
  });
}

Config

This tool stores configuration settings in two places. A global config is stored in the .rocketPDFConfig/ folder in the machine user's home directory. The second config is stored in .rocketPDF files stored in each project directory.

Global Config

The global config hosts settings which affect global operations. This includes the file API tokens for apps. File API tokens are applicable on the JourneyApps application ID level. An SQLite DB is used to store all the tokens. To update an application file API token run rocketPDF config set-token --appID=<appID>.

Local

The local .rocketPDF config files should not be committed to source repositories since they can contain secret credentials to the DB. The following commands are available to edit the data stored on the local config files.

  • rocketPDF config init: Resets the local configuration
  • rocketPDF config switchtask: Updates the corresponding CloudCode task
  • rocketPDF config switchdb: Updates the DB credentials

Readme

Keywords

none

Package Sidebar

Install

npm i @journeyapps-solutions/rocket-pdf

Weekly Downloads

0

Version

1.2.4

License

MIT

Unpacked Size

86.2 kB

Total Files

35

Last publish

Collaborators

  • journeyapps-solutions-publish
  • journeyapps-platform