Last active
November 4, 2022 03:35
-
-
Save szkrd/34c7695551b0359c2d8ed822072c84fa to your computer and use it in GitHub Desktop.
convert markdown to pdf using puppeteer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// first: `npm init -- yes && npm i -S [email protected] [email protected] [email protected] puppeteer-core` | |
// then: `node . --help` | |
const fs = require('fs'); | |
const http = require('http'); | |
const puppeteer = require('puppeteer-core'); | |
const showdown = require('showdown'); | |
const githubMarkdownCss = fs.readFileSync(require.resolve('github-markdown-css'), 'utf8'); | |
const handler = require('serve-handler'); // without serve loading local files, like images, would not be possible | |
const die = (text = '', code = 1) => process.exit(~~console.error(text) + code); | |
const ifHasParam = (s = '') => process.argv.includes(s); | |
const paramValueOf = (s = '') => (process.argv.find(x => x.startsWith(`${s}=`)) || '').split('=')[1]; | |
const asNum = (s = '') => (s || '').substr(0, 5).replace(/[^\d\.]/g, ''); | |
const VERSION = '1.2.0'; | |
const PDF_FORMAT = paramValueOf('--format') ?? 'A4'; | |
const MARGIN_CM = parseFloat(asNum(paramValueOf('--margin') ?? '1')) || 0; | |
const PORT = parseInt(asNum(paramValueOf('--port')), 10) || 31234; | |
const DEBUG = ifHasParam('--debug'); | |
let BROWSER_PATH = paramValueOf('--browser'); | |
if (!BROWSER_PATH && process.platform === 'linux') BROWSER_PATH = '/usr/bin/chromium'; | |
if (!BROWSER_PATH && process.platform === 'win32') BROWSER_PATH = 'C:/Program Files/Google/Chrome/Application/chrome.exe'; | |
if (!BROWSER_PATH && process.platform === 'darwin') BROWSER_PATH = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'; | |
let info = ''; | |
if (ifHasParam('--version')) info = `v${VERSION}`; | |
if (ifHasParam('--help')) info = 'Params (all optional):\n--help\n--version\n--port=31234\n--margin=1' + | |
'\n--debug\n--format=A4\n--browser=/usr/bin/chromium\n\nExample: node md2pdf sample.md'; | |
if (info) process.exit(~~console.info(info)); | |
if (process.argv.length <= 2) die('No filename specified, exiting...', 1); | |
const inputFileName = process.argv.slice(-1)[0]; | |
const outputFileName = inputFileName.replace(/\.md$/i, '.pdf'); | |
if (!fs.existsSync(inputFileName)) die(`Input file "${inputFileName}" not found.`, 2); | |
showdown.setFlavor('github'); | |
const inputText = fs.readFileSync(inputFileName, 'utf8'); | |
const renderedMd = (new showdown.Converter()).makeHtml(inputText); | |
const outputHtml = `<!DOCTYPE html><html lang="en"><head> | |
<meta charset="UTF-8"><title></title><base href="http://127.0.0.1:${PORT}/" /> | |
<style>${githubMarkdownCss}</style></head><body class="markdown-body">${renderedMd}</body></html>`; | |
let pup = { browser: null, page: null, server: null }; | |
async function quitPup(code = 0, message = '') { | |
if (message) console.info(message); | |
await pup.browser.close(); | |
pup.server.close(); | |
process.exit(code); | |
} | |
async function handleExit() { await quitPup(0, 'SIGINT Closing Puppeteer and Serve.'); } | |
console.info(`Launching Serve at port ${PORT}`); | |
pup.server = http.createServer((request, response) => handler(request, response, { directoryListing: DEBUG })); | |
pup.server.listen(PORT, '127.0.0.1'); | |
console.info('Launching Puppeteer'); | |
(async () => { | |
process.on('SIGINT', handleExit); | |
const args = ['--disable-crash-reporter']; | |
const headless = !DEBUG; | |
const browser = pup.browser = await puppeteer.launch({ headless, printBackground: true, format: PDF_FORMAT, executablePath: BROWSER_PATH, args }); | |
const page = pup.page = await browser.newPage(); | |
await page.setContent(outputHtml); | |
if (DEBUG) return; | |
const m = `${MARGIN_CM}cm`; | |
await page.pdf({ printBackground : true, path: outputFileName, margin: { top: m, right: m, bottom: m, left: m } }); | |
console.info('Closing Puppeteer'); | |
await browser.close(); | |
console.info('Closing Serve'); | |
pup.server.close(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment