NextPDF Artisan 概览
快速一览
标题为“快速一览”的章节NextPDF Artisan 是 NextPDF 的 Chrome 桥接。它通过 Chrome DevTools Protocol 将 HTML 片段发送到 headless Chrome 进程,捕获 printToPDF 的输出,再将结果作为 Form XObject 嵌入目标文档。嵌入后的文本仍可选取、可搜索。
概念总览
标题为“概念总览”的章节Artisan 软件包(nextpdf/artisan)为开源的 NextPDF 引擎扩展了一个将布局委派给 Chrome 的 renderer(渲染器)。NextPDF 原生 HTML 管线已覆盖相当广的 CSS 子集。Artisan 桥接面向需要 Chrome 级别布局能力的文档——CSS flexbox 与 grid、从 data URI 加载的自定义网页字体,以及复杂选择器——同时仍生成矢量文本,而非栅格化的屏幕截图。
这个桥接由一组小而职责单一的组件串成管线。ChromeHtmlRenderer 负责统筹一次绘制。ChromeSecurityPolicy 验证输入,并将其包进一份受严格限制的 HTML 文档。BrowserPool 管理 Chrome 进程的生命周期。ViewportCalculator 将 PDF 点数映射到 CSS 像素。NextPDF\Parser 读取器解析 Chrome 输出,再由 PageImporter 将其转换成 Form XObject。每个组件都是 final,采用构造函数注入,并以 PHPStan level 10 完整标注类型。
这个桥接依赖外部组件。它需要 chrome-php/chrome 库(^1.15),以及一个 PHP 进程可访问的 Chrome 或 Chromium 可执行文件。两者都不会随软件包附带。当该库不存在时,这个桥接会抛出 ChromeNotAvailableException,而不会无声降级——详见 /integrations/artisan/troubleshooting/ 页面上的 /integrations/artisan/failure-modes/ 一节。
在输入通过 ChromeSecurityPolicy::validate() 之前,绘制绝不会抵达 Chrome;而且 Chrome 收到的文档一律由严格的 Content-Security-Policy 和一道纵深防御的 CDP 网络封锁包裹。由于这个桥接可能处理不受信任的 HTML,它的传输与隔离设计在 /integrations/artisan/security-and-operations/ 页面上有明确记载,而不是在此摘要中一笔带过。
这是该软件包发布状态下观察到的行为,已对照 src/Artisan/ 与 tests/Unit/Artisan/ 测试套件验证。它并不声称与交互式 Chrome 浏览器逐像素一致:动画会以最终帧捕获,布局不依赖 JavaScript,而且只会导入第一个 Chrome 页面。
组件职责
标题为“组件职责”的章节| 组件 | 职责 | 来源 |
|---|---|---|
ChromeHtmlRenderer | 协调单次绘制;返回 ChromeRenderResult | src/Artisan/ChromeHtmlRenderer.php |
ChromeRendererConfig | 不可变的配置值对象 | src/Artisan/ChromeRendererConfig.php |
ChromeSecurityPolicy | 输入验证 + 安全的 HTML 封套 | src/Artisan/ChromeSecurityPolicy.php |
BrowserPool | Chrome 进程的生命周期与重启策略 | src/Artisan/BrowserPool.php |
ViewportCalculator | 72 pt/inch ↔ 96 px/inch 换算 | src/Artisan/ViewportCalculator.php |
ChromeRenderResult | 带类型的绘制输出(ChromeRenderResultInterface) | src/Artisan/ChromeRenderResult.php |
PageImporter | 已解析的 Chrome 页面 → ImportedFormXObject | src/Artisan/PageImporter.php |
EInvoiceServiceFactory | 供 Premium 电子发票合约使用的无容器工厂 | src/Artisan/EInvoiceServiceFactory.php |
边界情况与陷阱
标题为“边界情况与陷阱”的章节- **版本沿革。**发布到 Composer 的构件标记为
v0.1.0。源代码 docblock 带有@since 1.7.0(Chrome 桥接)与@since 1.1.0(电子发票工厂),两者都继承自更名前的nextpdf/core版本线;软件包更名为nextpdf/artisan的时间点,对应2.0.0的 CHANGELOG 条目。请将 Composer 标签视为权威的安装版本,并将@since标记视为引擎版本的 provenance(来源信息)。 - 仅限第一页。
PageImporter::import()默认使用页面 Index(索引)0。溢出到第二个 Chrome 页面的内容会被裁剪,除非明确指定高度——此点在 /integrations/artisan/production-usage/ 页面说明。 - 没有 DI 容器。 Artisan 不使用容器。
EInvoiceServiceFactory为没有服务容器的环境提供一致的实例化接口;参见 /integrations/artisan/boot-and-discovery/.
每次绘制都要付出一次 Chrome 加载页面与 printToPDF 的成本。BrowserPool 会让 Chrome 进程在多次绘制之间保持存活,并在每 100 次绘制后重启一次,以限制内存增长。主导 Big-O 的是 Chrome 对输入的布局成本,而非桥接本身。关于本页参考流程的实测预算,请见 frontmatter 中的 performance_budget 与 /integrations/artisan/production-usage/ 页面。
安全须知
标题为“安全须知”的章节这个桥接会在 Chrome 内绘制可能不受信任的 HTML。Chrome 接触输入之前,输入已先经过大小与内容验证。包裹后的文档带有 default-src 'none'。一道 CDP 级别的封锁会阻止所有子资源请求。完整的传输与隔离模型——包括 Chrome sandbox 标志的明确限制——记载于 /integrations/artisan/security-and-operations/ 页面。请勿把这一节视为完整的安全态势。
商业背景
标题为“商业背景”的章节开源桥接将 HTML 绘制成 PDF。Premium 各层级会在绘制好的文档之上,再叠加合规的电子发票嵌入(Pro)与验证(Enterprise)。当这些层级未安装时,EInvoiceServiceFactory 会返回 null,因此开源路径在没有它们的情况下仍完全可用。
- /integrations/artisan/install/——安装
- /integrations/artisan/configuration/——配置
- /integrations/artisan/quickstart/——快速上手
- /integrations/artisan/chrome-renderer-setup/——Chrome 渲染器设置
- /integrations/artisan/security-and-operations/——安全与运维
- /integrations/artisan/production-usage/——生产环境使用