@mofanx/md2pdf
Version:
高兼容性 Markdown 转 PDF 工具,支持本地图片、批量转换、字体优化,命令行一键使用。
61 lines (58 loc) • 2.1 kB
text/typescript
import fs from 'fs';
import path from 'path';
import MarkdownIt from 'markdown-it';
import puppeteer from 'puppeteer';
async function main() {
const inputPath = process.argv[2];
if (!inputPath) {
console.error('用法: pnpm dlx ts-node src/preview-html.ts <md文件路径>');
process.exit(1);
}
if (!fs.existsSync(inputPath)) {
console.error('输入文件不存在:', inputPath);
process.exit(1);
}
const mdContent = fs.readFileSync(inputPath, 'utf-8');
const md = new MarkdownIt({ html: true, linkify: true, typographer: true });
let htmlContent = md.render(mdContent);
const mdDir = path.dirname(path.resolve(inputPath));
// 替换本地图片路径为 file:// 绝对路径
htmlContent = htmlContent.replace(/<img([^>]*?)src=(["'])([^"'>]+)\2([^>]*)>/gi, (match, pre, q, src, post) => {
if (/^(http|https|data):/i.test(src)) return match;
let absPath = src.startsWith('/') ? src : path.join(mdDir, src);
absPath = path.resolve(absPath);
absPath = decodeURIComponent(absPath);
return `<img${pre}src=${q}file://${absPath}${q}${post}>`;
});
const html = `
<html>
<head>
<meta charset="utf-8">
<title>md2pdf-preview</title>
<style>
body { font-family: 'Arial', 'Microsoft YaHei', sans-serif; margin: 40px; }
pre, code { background: #f5f5f5; border-radius: 4px; }
img { max-width: 100%; height: auto; }
</style>
</head>
<body>${htmlContent}</body>
</html>
`;
// 写入临时 html 文件
const tmpHtmlPath = path.join(mdDir, '__md2pdf_preview.html');
fs.writeFileSync(tmpHtmlPath, html, 'utf-8');
// 用 puppeteer 有头模式打开
const browser = await puppeteer.launch({
headless: false,
args: [
'--no-sandbox',
'--disable-setuid-sandbox',
'--allow-file-access-from-files',
'--enable-local-file-accesses'
],
});
const page = await browser.newPage();
await page.goto('file://' + tmpHtmlPath);
console.log('已在浏览器中打开,按F12可查看控制台和网络面板。');
}
main();