Markdown 转 PDF 命令行工具开发:使用 PureScript 和 Puppeteer
随着信息时代的到来,Markdown 文档因其简洁、易读和易编辑的特性,已经成为许多开发者、内容创作者的首选格式。Markdown 文档在阅读体验上往往不如 PDF 格式,特别是在打印或展示时。为了解决这个问题,我们可以开发一个命令行工具,将 Markdown 文档转换为 PDF 格式。本文将介绍如何使用 PureScript 语言和 Puppeteer 库来实现这一功能。
PureScript 是一种函数式编程语言,它基于 Haskell,旨在提供一种简洁、高效且易于维护的编程方式。Puppeteer 是一个 Node.js 库,它提供了一个高级 API 来控制 Chrome 或 Chromium。结合这两个工具,我们可以轻松地将 Markdown 文档转换为 PDF。
环境准备
在开始之前,请确保你已经安装了以下软件:
- Node.js 和 npm
- PureScript 和 spago(PureScript 的构建工具)
- Chrome 或 Chromium 浏览器
创建项目
创建一个新的 Node.js 项目:
bash
mkdir markdown-to-pdf
cd markdown-to-pdf
npm init -y
然后,安装所需的依赖:
bash
npm install puppeteer purescript-spago
接下来,创建一个名为 `src` 的目录,并在其中创建一个名为 `Main.purs` 的文件。
编写 PureScript 代码
在 `Main.purs` 文件中,我们将编写一个函数来读取 Markdown 文档,使用 Puppeteer 打开一个新页面,将 Markdown 内容渲染为 HTML,然后导出为 PDF。
```purescript
module Main where
import Effect (Effect)
import Effect.Aff (Aff)
import Effect.Class (liftEffect)
import Node.Encoding (Encoding)
import Node.FS (FS)
import Node.FS.Sync (readTextFile)
import Node.Path (FilePath)
import Node.Process (argv)
import Spago.Command (run)
import Spago.Config (Config)
import Spago.Core (Spago)
import Spago.Task (Task)
import Spago.Task.Build (build)
import Spago.Task.Lint (lint)
import Spago.Task.Test (test)
import Spago.Task.Types (TaskName)
import System.FilePath (FilePath, (>))
import Text.Pandoc (readMarkdown)
import Text.Pandoc.Writers (writePdf)
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Pandoc (runPandoc)
import Text.Pandoc.PandocOptions (PandocOptions)
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as Options
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import Text.Pandoc.PandocOptions as PandocOptions
import</p>
Comments NOTHING