uni-app publishes one codebase to H5, WeChat mini programs, and native Apps, which is convenient for business but makes capabilities like "export PDF" genuinely tricky: mini programs have no browser DOM, and App environments vary by platform, so many PDF libraries simply cannot run across all targets. dompdf.js is a pure frontend DOM-to-PDF engine: on the H5 end of uni-app it renders the page DOM directly, and although mini programs have no DOM, addPage also accepts HTML strings, so well-formed PDFs are still possible. This guide covers integration approaches, code examples, and caveats for all three runtime environments — H5, mini program, and App — so you can pick the right export path per platform. The key architectural decision is to treat PDF generation as a pure function of content: once the content is expressed as a DOM node or an HTML string, the same library call produces the same document on every platform that can host it. This guide also explains where each platform's limits are, so teams can set expectations with stakeholders honestly — the H5 end is fully featured, while mini programs trade a few capabilities for the platform's constraints. By the end, you will have a platform matrix in mind: DOM export on H5, string export in mini programs, and WebView delegation on App — and the shared module that ties them together.
uni-app's three runtime environments differ substantially: H5 is a standard browser, mini programs are a restricted JavaScript runtime, and Apps use WebView or native rendering. Library selection must account for these differences rather than assuming a browser environment. The differences are not cosmetic: a library that works flawlessly on H5 can crash at runtime inside a mini program the moment it touches document or window, so capability planning must happen before implementation.
Many PDF libraries depend on the browser DOM and cannot run inside mini programs at all. Others produce low-quality output (bitmap screenshots, non-selectable text), and still others require backend cooperation — none of which unifies cleanly in a cross-platform architecture. Settling on one abstraction — content in, PDF out — keeps the team's mental model simple even as the platform layer changes underneath.
The key insight is that "export PDF" fundamentally means "lay out structured content as a document." dompdf.js accepts both DOM nodes and HTML strings as input, which provides a unified integration path across all three runtimes — the cornerstone of cross-platform use. Cross-platform projects fail on export features more often than on any other capability, precisely because the environment differences are underestimated until the release build.
User expectations also differ by platform: H5 users expect a download, mini program users expect a share card or a document preview, and App users expect a native-looking export flow; matching the platform's idiom is part of the design.
Budgeting for platform differences early prevents the classic failure mode where the H5 prototype works perfectly and the mini program build is blocked at release time.
Because dompdf.js accepts both DOM and string input, the platform abstraction is a thin layer: each environment adapts its input type, and the rendering engine stays identical.
A useful planning exercise is to write the export requirement as platform-agnostic acceptance criteria — 'the user obtains a PDF of the report' — and then let each platform decide how to satisfy it; this keeps the feature honest on every target.
On H5, the environment is a standard browser, so dompdf.js works exactly as in any web project: pass the page DOM node to addPage and export a what-you-see-is-what-you-get PDF with the fullest feature set. The H5 build is also the natural place to demo and iterate on templates, since the full browser tooling — devtools, live reload, style inspection — applies directly.
Use conditional compilation (#ifdef H5) to confine the export logic to the H5 build and give other platforms their own path. The code stays clean and isolated, and the mini program build never pulls in DOM-dependent logic that would throw at runtime. Feature parity on H5 means the export module can be tested exhaustively there before the platform-specific wrappers are even written.
The H5 end has no platform restrictions: fonts, images, pagination, headers and footers are all available. It is the right choice for admin dashboards, H5 reports, and mobile reporting scenarios that demand document quality. Because H5 runs in a real browser, every dompdf.js feature — fonts, images, pagination, headers and footers — is available without workarounds.
Conditional compilation is the official mechanism for exactly this kind of divergence, and it works at build time: dead code is stripped from the bundle rather than guarded at runtime.
For H5-only projects (or projects where H5 is the primary target), the export feature can simply be built as a standard Vue page with no conditional blocks at all, keeping the codebase as simple as possible.
When the H5 build is embedded in a mini program WebView later, the same page doubles as the App export surface — one implementation, two deployments.
Conditional compilation comments take effect at build time: the H5 bundle contains only browser code, while the mini program bundle never includes DOM-dependent export logic, eliminating runtime errors at the source and keeping bundle sizes clean. The ref-based capture works identically to plain Vue, so developers coming from a Vue background can port the export feature almost without reading the docs.
Mark the export region with a ref (such as this.$refs.report), exactly as in regular Vue usage. Trigger export only after API data has loaded to avoid producing blank documents. Showing platform-specific feedback — a toast on mini programs, a download on H5 — keeps the user experience honest about what each environment can do.
On mini programs, show a friendly toast instead, guiding users toward "generate share card" or a backend PDF fallback. The feature remains usable on every platform — only the implementation path differs. Because the branches are compile-time, the final bundles contain no dead platform code, which also keeps the mini program package audit-friendly.
A loading guard is worth adding to the H5 branch: while the WASM engine initializes on first use, show a spinner so the first export does not feel like a hang.
Because the H5 branch is isolated by conditional compilation, regressions in one platform's code can never leak into another build — a genuine maintenance win for small teams.
Teams that later add a third target, such as an Alipay mini program, simply extend the conditional blocks; the core export logic remains untouched.
When debugging conditional compilation, remember that the preprocessor runs before bundling: a syntax error inside an excluded branch can still surface in some toolchains, so keep both branches valid at all times.
// pages/report/report.vue
import { DomPDF } from 'dompdf.js';
export default {
methods: {
async exportPdf() {
// #ifdef H5
const pdf = new DomPDF();
pdf.addPage(this.$refs.report, { format: 'A4', margin: '15mm' });
pdf.save('report.pdf');
// #endif
// #ifdef MP-WEIXIN
uni.showToast({ title: 'Please use share or backend export on mini program', icon: 'none' });
// #endif
}
}
}
Mini programs have no browser DOM, so DOM nodes cannot be passed. However, addPage accepts HTML strings: assemble the data into a template string and generate the PDF. The core logic stays highly consistent with the H5 path, so reuse costs are low. The string approach also makes the mini program path deterministic: because the template is assembled from data, the same input always produces the same PDF, which simplifies QA across devices.
Mini programs face network and package-size constraints. Host dompdf.js and its WASM file on a CDN or deliver them on demand from the backend to avoid bloating the mini program's main package, which affects review and loading speed. String templates can be shared verbatim between H5 and mini programs, so the document design stays consistent even though the input type differs.
For file download and preview, mini programs can use wx.downloadFile together with wx.openDocument to open the PDF, or guide users to obtain the file via email or cloud storage — matching mobile usage habits. Escaping rules apply doubly here, since mini program data often comes from user input inside form pages; escape every interpolated field before building the template.
Mini program subpackage strategy matters: if dompdf.js ships inside the main package, the download size limit can block release; hosting the engine on a CDN and loading it on demand keeps the package audit-friendly.
For preview and sharing, the document-open API covers most needs, but remember that the user must have a PDF viewer available; offering a share-image fallback covers the long tail of devices.
Because mini program network requests are rate-limited, cache the engine and WASM after first load, and consider bundling the template strings locally so only the data travels over the network.
For mini program templates that grow long, split the HTML string into composable fragments (header, body table, footer) and concatenate them; the code stays readable and each fragment can be reviewed and tested independently.
On the App end, uni-app typically renders through a WebView. Load an H5 page inside the WebView and let that H5 page perform PDF generation, so the export capability is implemented once and reused across platforms. The WebView approach is the closest thing to write-once-run-anywhere on App: the H5 page already has the full feature set, so the App inherits it wholesale.
Alternatively, package the export capability as a standalone H5 page, open it in the App with a web-view component, pass parameters in, and relay the generated result back through the web-view message channel for a unified export interaction. Communication between the App shell and the WebView uses the standard message channel, so results and parameters flow in both directions without native plugins.
If the App uses native rendering (nvue), prefer backend generation or jumping to an H5 page for PDF export. Prioritize feature consistency and keep native-side maintenance costs low. Because the export runs inside the WebView, the App's own UI thread is never blocked, and the WebView can show the same progress feedback as the H5 build.
If the App must show a native loading indicator during export, the H5 page can post a status message through the channel, letting the native side mirror the progress.
For Apps that ship on several platforms, the WebView route also equalizes behavior: the same H5 page renders the same PDF everywhere, avoiding platform-specific quirks in native PDF code.
When the export output must be saved to the device, the native side can intercept the generated blob and write it to the app's document directory, integrating the PDF with the app's own file management.
If the App target uses a third-party WebView wrapper, verify that the message channel and the file-save bridge match the wrapper's documented API before writing the integration; most support issues trace back to bridge mismatches.
Q: How much does the bundle grow after integration? A: dompdf.js includes WASM, so load it on demand (dynamic import) and split chunks at build time to avoid hurting first-screen load performance. Measuring after integration is wise: compare first-screen bytes before and after, and keep the dynamic import path so non-export users never pay the WASM cost.
Q: Will Chinese be garbled in mini programs? A: No. The built-in Source Han Sans SC font renders proper Chinese through the HTML string approach too, identical to the H5 result. The string path renders with the same built-in font as H5, so the same template produces the same glyphs on both ends.
Q: Do I need to write three separate implementations? A: No. Extract the core export logic into a shared module; only the runtime-environment parts need conditional compilation. The majority of the code is reusable across all three platforms. Any capability question on mini programs should be answered against the platform's actual API surface, not against browser assumptions.
Q: Does the mini program path support images? A: Yes — data URLs and remote URLs both work; for remote images, ensure the domain is whitelisted in the mini program's download settings, or embed the images as base64 in the template.
Q: How do I test the App path without a device? A: Use the H5 build in a desktop browser first — the WebView renders the same page — then verify on one real device per OS to catch channel and file-saving specifics.
Q: Can the same codebase export on H5 and in the App without duplication? A: Yes — the H5 page used for the App WebView is the same component the H5 build renders, so the export logic is written once and mounted in two places.
下面的按钮用 dompdf.js 在浏览器端实时生成 PDF,无需后端:
这是由 dompdf.js 渲染的示例 PDF 内容。