Source: server/src/utils/elementToImage.js

/**
 * @module server/utils/elementToImage
 */

const fs = require('fs')
const ReactDOMServer = require('react-dom/server')
const webshot = require('webshot')

const stylesTagContent = fs.readFileSync('./dist/styles.css')

/**
 * converts React element to html
 * @param element {object} React element
 * @returns {string} HTML of the element
 */
module.exports = function elementToImage (element) {
  let elementHtml = elementToHtml(element)
  return htmlToImageAsync(elementHtml)
}

function elementToHtml (element) {
  const body = ReactDOMServer.renderToStaticMarkup(element)
  const html = `<!doctype html>
      <html>
        <head>
          <style>
            ${stylesTagContent}
          </style>
        </head>
        <body>
          <div>
            ${body}
          </div>
        </body>
      </html>`

  return html
}

function htmlToImageAsync (html) {
  return new Promise(function (resolve, reject) {
    var options = {
      siteType: 'html'
    }
    let renderStream = webshot(html, null, options)
    let screenshot = ''

    // Capture the streaming output from the screenshot
    renderStream.on('data', function (data) {
      screenshot += data.toString('binary')
    })

    // Once the image capture is completed, write it out to the browser
    renderStream.on('end', function () {
      let asBase64 = Buffer.from(screenshot, 'binary').toString('base64')
      resolve(asBase64)
    })
  })
}