← dompdf.js Studio

Vite 项目集成 dompdf.js 指南

Vite 以极快的开发服务器和开箱即用的 ESM 支持成为现代前端的事实标准,但它的依赖预构建与静态资源处理机制,对 WASM 类库的集成提出了特殊要求:dompdf.js 包含 Rust/WASM 内核与 Worker 管线,如果不在 vite.config.js 里做好配置,开发环境可能正常、生产构建却报错,或者 wasm 文件路径解析失败导致运行时崩溃。本文从安装与基础用法讲起,给出 vite.config.js 中 optimizeDeps、worker 与静态资源的完整配置,再介绍 Worker 模块化加载的正确姿势,最后汇总常见报错与排查方法,帮你一次配置到位,让 PDF 导出功能稳定运行。

为什么 Vite 项目需要特殊配置

Vite 开发模式下依赖以原生 ESM 加载,生产模式用 Rollup 打包,两套机制对依赖的处理方式不同。dompdf.js 这类带二进制资源与 Worker 的库,在预构建阶段如果被强制打包,Worker 与 wasm 的路径引用可能失效;把这类依赖加入 optimizeDeps.exclude,让浏览器按原生 ESM 加载,是最常见的解法,也是官方文档里针对 WASM 依赖的标准建议。

另一个关键点是 wasm 文件的处理:Vite 默认把 .wasm 当作静态资源输出,但如果库内部通过 fetch 加载 wasm 且路径基于 import.meta.url 计算,构建后的资源路径必须与部署路径一致。配置 assetsInclude 或在构建后检查资源引用,可以避免 wasm 404 这类运行时错误,这类错误在开发环境通常不出现,上线后才暴露,所以更要提前配置。

好消息是这些配置都是一次性的:配好后开发、构建、部署全链路稳定,团队其他成员直接复用。理解配置背后的原理,包括预构建、资源内联、路径解析,遇到新报错也能举一反三,而不是把配置当咒语抄来抄去;原理清楚了,任何构建工具的集成问题都能自己排查。

还要注意版本匹配:dompdf.js 升级后,配置一般不需要变,但如果新版本改变了资源加载方式,要对照更新日志检查配置是否仍然有效。把版本与配置的对应关系记录在项目文档里,升级时按文档核对,可以避免升级引发的隐性故障,排查问题时也多了一条线索,团队协作更顺畅。

安装与基础集成

先安装依赖,然后在业务组件里按需引入。基础用法非常直接:创建 DomPDF 实例,addPage 添加 HTML 或元素,save 触发下载。注意 PDF 导出属于重型操作,建议封装成独立的导出模块,避免散落在各个组件里,后续维护与性能优化都集中在一点,调用方只面对一个简单的函数签名。

封装时把格式、边距等参数作为配置项传入,业务组件只关心导出这份数据,不关心 PDF 细节。参数默认值放在封装函数内部,特殊需求通过参数覆盖,接口收敛、行为可预期,测试也好写,这是集成类代码的通用做法,也方便后续在封装内部接入 Worker、进度等增强能力而不影响调用方。

如果项目使用 TypeScript,记得确认类型声明可用,编辑器才能正确提示 DomPDF 的类型;类型提示到位,调用 addPage、save 时参数错误能在编译期暴露,而不是运行时才发现,集成体验会顺畅很多,重构时编辑器也能自动同步所有调用点。

// 安装依赖
// npm install dompdf.js

// export-report.js —— 封装导出逻辑
import { DomPDF } from 'dompdf.js';

export async function exportReport(html, filename = 'report.pdf') {
  const pdf = new DomPDF();
  pdf.addPage(html, { format: 'A4' });
  pdf.save(filename);
}

代码示例:vite.config.js 完整配置

下面这份配置覆盖了 dompdf.js 集成的三个要点:optimizeDeps.exclude 让依赖跳过预构建,worker.format 指定 Worker 打包格式,assetsInclude 把 wasm 明确纳入资源处理。三行配置解决三类问题,缺一不可,复制到你的项目里按需微调即可,配置项的含义与库的内部实现一一对应,理解之后就不会觉得这是玄学。

配置里的每一项都有明确目的:exclude 避免预构建改写依赖内部路径,导致 Worker 或 wasm 引用失效;worker.format 设为 es 让 Worker 以 ESM 格式输出,与模块 Worker 的 import 语法匹配;assetsInclude 确保 wasm 文件被当作资源正确处理并输出到构建目录。build.target 设 es2020 是为了兼容现代浏览器对 wasm 与模块语法的要求,按你的目标浏览器调整即可。

配置生效后可以做个快速验证:开发环境跑一次导出,构建产物跑一次导出,两次都成功且结果一致,说明配置完整覆盖了两套构建链路。把这两步验证写进集成验收清单,后续任何人改动构建配置,都能快速确认没有破坏 PDF 导出,回归成本几乎为零,团队维护起来很省心。

// vite.config.js
import { defineConfig } from 'vite';

export default defineConfig({
  optimizeDeps: {
    exclude: ['dompdf.js'],
  },
  worker: {
    format: 'es',
  },
  assetsInclude: ['**/*.wasm'],
  build: {
    target: 'es2020',
  },
});

Worker 与 import.meta.url 的正确用法

在 Vite 项目里创建 Worker 有两种方式:new Worker(new URL('./worker.js', import.meta.url), { type: 'module' }) 是官方推荐写法,Vite 会识别并单独打包 Worker 文件;或者用 ?worker 后缀导入,返回 Worker 构造函数,适合需要动态参数的场景。两种方式都要避免把 Worker 代码写在字符串里,否则无法被构建工具处理,路径也会解析失败。

dompdf.js 内部使用 Worker 管线时同样依赖路径解析,Vite 的正确配置能保证打包后 Worker 与 wasm 文件都被正确输出。如果你自己封装了导出 Worker,记得把 Worker 文件放在 src 目录内,让构建工具能发现并处理它;放在 public 目录的文件不会经过打包,引用路径容易出问题,也不会有内容哈希带来的缓存优化。

如果遇到 Worker 内部无法使用 import 的情况,检查打包产物里 Worker 文件的格式:Vite 按 worker.format 配置输出,es 格式对应模块 Worker,iife 格式对应经典 Worker。两种格式与 Worker 创建方式的 type 参数必须匹配,创建与打包不一致是最常见的运行时错误来源,对照检查一遍即可解决,配置统一后不会再反复出现。

开发服务器与生产构建的差异

开发模式下 Vite 按需编译、依赖预构建,dompdf.js 以原生 ESM 加载,wasm 由 dev server 提供,路径问题少;生产构建经过 Rollup 打包,资源会加上内容哈希并输出到 dist 目录,如果代码里硬编码了资源路径,构建后必然 404。所有资源引用都走相对路径或 import 方式,生产环境才不会出问题,这是 Vite 集成的第一原则。

部署时的 base 配置也要注意:如果应用部署在子路径,比如 https://example.com/app/,vite.config.js 的 base 必须对应设置,否则 wasm、Worker、字体等资源的绝对路径全部失效。资源路径问题有一个共性排查思路:打开生产站点的 Network 面板,看哪个资源 404,再顺着它的引用链找到配置出处,通常几分钟就能定位。

性能上还有一个差异值得注意:开发模式不做压缩与 tree shaking,dompdf.js 的加载体积会比生产大,首次导出稍慢是正常的,不要据此判断生产性能。以生产构建为准做性能基准,记录基线数据,后续优化前后对比才有意义,避免在开发环境里做无谓的优化,把精力花在真正影响用户的地方。

常见问题排查

Q: 开发正常,构建后导出报错?A: 优先检查三处:optimizeDeps.exclude 是否配置、wasm 是否被正确输出到 dist、Worker 是否以模块方式加载。绝大多数构建期问题都出在这三处,按顺序排查命中率极高,每一项都有对应的配置项,对着检查清单过一遍基本能解决。

Q: 控制台报 wasm 404?A: 确认 assetsInclude 与 base 配置,检查 dist 目录里 wasm 文件的实际路径与请求路径是否一致;使用相对路径引用资源,或部署时把资源放在同一路径层级,问题即可解决,缓存策略也要同步检查,避免旧缓存干扰。

Q: Worker 文件没有被打包?A: 检查 Worker 创建方式是否用了 new URL 加 import.meta.url 的规范写法,确保 Worker 文件位于 src 内;不要用字符串路径创建 Worker,构建工具无法解析。按这三问排查,Vite 集成问题基本都能快速定位,配置一次到位后,后续迭代几乎不会再碰构建问题。

最后一个通用建议:把 vite.config.js 里与 dompdf.js 相关的配置集中注释说明,团队成员看到配置能立刻明白每一项的用途,新项目接入时直接复制注释与配置,不需要重新踩一遍坑。配置即文档,是构建类代码最好的维护方式,长期来看能省下大量沟通与排查成本。

⚡ 现场演示(点击生成 PDF)

下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:

Hello from dompdf.js!

这是由 dompdf.js 渲染的示例 PDF 内容。