Skip to content

Instantly share code, notes, and snippets.

@onesamket
Forked from akerouanton/md2pdf.js
Created November 22, 2024 20:57
Show Gist options
  • Save onesamket/593777be611092c4b5ccc1f01a4417e8 to your computer and use it in GitHub Desktop.
Save onesamket/593777be611092c4b5ccc1f01a4417e8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env node
const Remarkable = require('remarkable');
const toc = require('markdown-toc');
const fs = require('fs');
const puppeteer = require('puppeteer');
const express = require('express');
const generateHtml = (file, serverAddress) => {
const md = new Remarkable({
html: true,
linkify: true,
typographer: true,
quotes: '«»',
});
// @see https://github.com/jonschlinkert/remarkable/issues/122#issuecomment-150011254
md.use(function(remarkable) {
remarkable.renderer.rules.heading_open = (tokens, idx) =>
'<h' + tokens[idx].hLevel + ' id=' + toc.slugify(tokens[idx + 1].content) + '>';
});
const content = toc.insert(fs.readFileSync(file, 'utf8'));
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="stylesheet" href="${serverAddress}/dist/css/style.css">
<title>YOLO</title>
<style>
@page { margin: 5% 5%; }
body { padding: 20px; }
.page-break { page-break-after: always; }
table { page-break-inside:auto }
thead, tbody { display: table-row-group; }
tr { page-break-inside:avoid; page-break-after:auto }
.version td { height: 37px; }
.version tr td:nth-of-type(3) { width: 60%; }
</style>
</head>
<body class="markdown-body">${md.render(content)}</body>
</html>`;
}
const argv = process.argv.slice(2);
if (argv.length !== 2) {
console.error('Usage: md2pdf <md-file> <pdf-dest>');
process.exit(1);
}
const html = generateHtml(argv[0]);
const server = express();
const listener = server.listen(0); // Let the kernel pick a random port
const address = `http://localhost:${listener.address().port}`;
console.log(address);
server.get('/', (req, res) =>
res.send(generateHtml(argv[0], address))
);
server.use('/dist', express.static(__dirname + '/dist'));
server.use('/resources', express.static('resources'));
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(address);
await page.pdf({
path: argv[1],
displayHeaderFooter: true,
headerTemplate: '<p style="text-align: center; font-size: 9px; width: 100%; margin-top: -4px;"><span class="title"></span></p>',
footerTemplate: '<p style="text-align: right; font-size: 9px; width: 100%; margin-bottom: -4px; padding-right: 3%;"><span class="pageNumber"></span> / <span class="totalPages"></span></p>',
printBackground: true,
});
await browser.close();
listener.close();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment