Replace wicked_pdf with puppeteer

Replace wicked_pdf with puppeteer

kawasaki.rb #073〜6周年記念LT大会
https://kawasakirb.connpass.com/event/134375/

851704b2aa97d2117dc89bf60a2cd272?s=128

tanakaworld

June 26, 2019
Tweet

Transcript

  1. Replace wicked_pdf with puppeteer kawasaki.rb #073〜6周年記念LT大会 2019/06/26 @_tanakaworld

  2. About Me • Twitter: @_tanakaworld • GitHub: tanakaworld • Merpay,

    inc. • Software Engineer (Frontend)
  3. https://proff.io/

  4. wicked_pdf • PDF generator (from HTML) plugin for Ruby on

    Rails ◦ https://github.com/mileszs/wicked_pdf • Uses wkhtmltopdf ◦ https://wkhtmltopdf.org/
  5. Issues of wicked_pdf • Limited Markup of CSS / HTML

    (undocumented) • Too slow
  6. puppeteer • https://github.com/GoogleChrome/puppeteer • Headless Chrome • Able to ◦

    take screenshot ◦ control Web Page ◦ make PDF ◦ •••
  7. HTML -> PDF • HTML Requirements ◦ Unable to make

    HTML public ◦ Authorization in Rails App
  8. Use puppeteer in Rails App • HTML Requirements ◦ Unable

    to make HTML public ◦ Authorization in Rails App • Install ◦ $ yarn add puppeteer • Flow ◦ Authentication / Authorization ◦ Generate HTML file ◦ Generate PDF file from HTML file (by puppeteer) ◦ Respond PDF file
  9. articles/1 articles/1.pdf DEMO

  10. class ArticlesController < ApplicationController include PdfHelpers ••• def show template_path

    = 'articles/show.html.erb' respond_to do |f| f.html do @is_pdf = false render template_path end f.pdf do @is_pdf = true render_pdf_from_template "#{@article.title}-#{Time.zone.now.to_date.to_s}", template_path end end end ••• end
  11. require 'securerandom' module PdfHelpers extend ActiveSupport::Concern def render_pdf_from_template(file_name, template_path) data_html

    = render_to_string template_path, layout: 'pdf' FileUtils.mkdir_p(tmp_pdf_dir) unless File.exists?(tmp_pdf_dir) html_file_path = generate_html_from_template(data_html) pdf_data = generate_pdf_from_html(html_file_path) render_pdf_data(pdf_data, "#{file_name}.pdf") rescue => e logger.error e end •••
  12. private def tmp_pdf_dir "#{Rails.root}/tmp/pdf-generator" end def log_path ENV['RAILS_ENV'] === 'development'

    ? "#{tmp_pdf_dir}/app.log" : '/var/log/pdf-generator/app.log' end def generate_html_from_template(data) tmp_html_file = File.open("#{tmp_pdf_dir}/#{SecureRandom.hex}.html", "w") tmp_html_file.puts data tmp_html_file.close tmp_html_file.path end def generate_pdf_from_html(html_path) tmp_pdf_file = Tempfile.new("#{SecureRandom.hex}") system("node #{Rails.root}/pdf-generator/pdf-from-html-file.js #{html_path} #{tmp_pdf_file.path} > #{log_path} 2> #{log_path}") File.read(tmp_pdf_file.path) end def render_pdf_data(data, file_name) send_data(data, filename: file_name, type: 'application/pdf', disposition: 'inline') end end
  13. const puppeteer = require('puppeteer'); const createPdf = async () =>

    { let browser; try { browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); const page = await browser.newPage(); const htmlPath = process.argv[2]; await page.goto(`file:${htmlPath}`, { waitUntil: 'networkidle0' }); await page.pdf({ path: process.argv[3], format: 'A4', margin: {top: 0, right: 0, bottom: 0, left: 0}, printBackground: true }); } catch (err) { console.error(err.message); } finally { if (browser) { browser.close(); } process.exit(); } }; createPdf();
  14. articles/1 articles/1.pdf

  15. Summary • You can integrate puppeteer in Rails App •

    Easy to ◦ convert HTML to PDF ◦ wait something… ▪ e.g. page.waitForSelector • You should separate PDF generation process if needed
  16. Sample • https://github.com/tanakaworld/puppeteer_on_rails_sample

  17. Thanks