Skip to content

fix(pdf): serve embedpdf runtime assets from same origin#3941

Merged
Crash-- merged 2 commits into
masterfrom
fix/pdf-self-host-embedpdf-assets
Jun 22, 2026
Merged

fix(pdf): serve embedpdf runtime assets from same origin#3941
Crash-- merged 2 commits into
masterfrom
fix/pdf-self-host-embedpdf-assets

Conversation

@Crash--

@Crash-- Crash-- commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Copy the Pdfium wasm, the default stamp library and the glyph-fallback fonts into build/static and point the PDF editor at those same-origin paths, so they no longer load from jsDelivr (blocked by the CSP).
  • Disable the EmbedPDF Google Fonts UI and signature webfonts, falling back to the system font stack.
  • Ship only Latin Regular/Bold fallback fonts and drop the duplicate Pdfium wasm rspack emits, keeping the build tarball under the 20 MB registry limit.

Summary by CodeRabbit

  • New Features
    • Updated the PDF editor to self-host PDF runtime assets (including PDFium WASM and stamp manifests) from the app origin for smoother, more reliable loading.
    • Added configurable font fallback/snippet font behavior and improved multilingual font support (notably Arabic and Hebrew).
  • Tests
    • Added automated Jest coverage to verify generated asset URLs and runtime configuration.
  • Chores
    • Updated project dependencies to include required EmbedPDF runtime packages and assets.

EmbedPDF fetched the Pdfium wasm, the default stamp library and its
glyph-fallback fonts from jsDelivr, which the production CSP blocks.
Copy them into build/static (served by the public /static route) and
point the viewer at those same-origin paths, and disable the Google
Fonts UI/signature webfonts.

To stay under the registry size limit, only the Latin Regular and Bold
fallback fonts ship (CJK is omitted) and the bundled Pdfium wasm copy
rspack emits from `new URL` is dropped before emit, since the engine
loads the wasm from the copied file instead.
@coderabbitai

coderabbitai Bot commented Jun 21, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 784c862e-6ba2-4bc5-97f6-c784dfc89efe

📥 Commits

Reviewing files that changed from the base of the PR and between 52a494c and d58d9a7.

📒 Files selected for processing (2)
  • src/modules/views/Pdf/pdfAssets.js
  • src/modules/views/Pdf/pdfAssets.spec.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/modules/views/Pdf/pdfAssets.js

Walkthrough

This PR self-hosts EmbedPDF runtime assets to eliminate external CDN dependencies. Six new @embedpdf/* packages are added to package.json. A new pdfAssets.js module centralizes runtime configuration by exporting a PDFIUM_WASM_URL pointing to /static/pdfium.wasm, a locale-aware STAMP_MANIFESTS array, a FONT_FALLBACK map from FontCharset values to self-hosted font variant arrays, and SNIPPET_FONTS that nulls out external Google Fonts loading. Tests verify all exported URLs are absolute. PdfEditor.jsx imports and wires these exports into the PDFViewer config. rsbuild.config.mjs is extended to copy the PDFium WASM, stamp assets, and font files into build/static/ subdirectories, and adds an Rspack emit hook that removes bundled *.module.wasm artifacts from the compilation output.

Suggested reviewers

  • doubleface
  • zatteo
  • lethemanh
  • JF-Cozy
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(pdf): serve embedpdf runtime assets from same origin' accurately describes the main change: relocating EmbedPDF runtime assets from external CDN to same-origin server.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/pdf-self-host-embedpdf-assets

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@bundlemon

bundlemon Bot commented Jun 21, 2026

Copy link
Copy Markdown

BundleMon

Files updated (1)
Status Path Size Limits
static/js/async/(chunkId).(hash).js
7.5KB (+5.44KB +264.17%) -
Unchanged files (19)
Status Path Size Limits
static/js/cozy.(hash).js
928.17KB -
static/resource/(hash).js
336.09KB -
services/qualificationMigration.js
283.39KB -
services/dacc.js
263.13KB -
static/js/main.(hash).js
48.27KB -
static/js/lib-react.(hash).js
43.88KB -
static/css/cozy.(hash).css
30.13KB -
static/js/lib-polyfill.(hash).js
22.77KB -
static/js/lib-router.(hash).js
21.86KB -
static/js/public.(hash).js
19.79KB -
static/css/main.(hash).css
13.57KB -
static/js/intents.(hash).js
9.2KB -
static/js/(chunkId).(hash).js
8.6KB -
manifest.webapp
3.09KB -
static/css/public.(hash).css
2.34KB -
index.html
769B -
public/index.html
704B -
intents/index.html
645B -
assets/manifest.json
185B -

Total files change +5.44KB +0.27%

Groups updated (1)
Status Path Size Limits
**/*.js
5.98MB (+2.19KB +0.04%) -
Unchanged groups (2)
Status Path Size Limits
**/*.{png,svg,ico}
2.16MB -
**/*.css
77.42KB -

Final result: ✅

View report in BundleMon website ➡️


Current branch size history | Target branch size history

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
rsbuild.config.mjs (1)

160-162: Add cardinality guard to WASM deletion hook to future-proof against multiple WASM sources.

The deletion pattern at line 161 targets static/wasm/*.module.wasm broadly, not specifically by pdfium hash or metadata. Currently, only @embedpdf/pdfium uses the new URL('...') pattern that triggers rspack's asyncWebAssembly bundling to this location. However, if another dependency later emits WASM through the same mechanism, its JS reference would remain but the asset would be silently deleted at runtime, causing 404 errors.

Harden the hook with cardinality assertion:

Suggested fix
-                  for (const name of Object.keys(compilation.assets)) {
-                    if (/static[\\/]wasm[\\/].*\.module\.wasm$/.test(name)) {
-                      delete compilation.assets[name]
-                    }
-                  }
+                  const bundledWasmAssets = Object.keys(compilation.assets).filter(
+                    name => /static[\\/]wasm[\\/].*\.module\.wasm$/.test(name)
+                  )
+
+                  if (bundledWasmAssets.length > 1) {
+                    throw new Error(
+                      `Refusing to delete multiple bundled WASM assets: ${bundledWasmAssets.join(', ')}`
+                    )
+                  }
+
+                  for (const name of bundledWasmAssets) {
+                    compilation.deleteAsset?.(name) ?? delete compilation.assets[name]
+                  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@rsbuild.config.mjs` around lines 160 - 162, The WASM deletion hook in the
loop that iterates over Object.keys(compilation.assets) uses a broad regex
pattern to delete files matching `/static[\\/]wasm[\\/].*\.module\.wasm$`
without verifying the expected cardinality. Add a cardinality assertion before
or after the deletion loop to verify that exactly one WASM file matches the
pattern, ensuring that if multiple WASM sources are added in the future, the
hook will fail safely rather than silently deleting unexpected assets. This can
be done by counting the matches against the regex pattern and asserting that the
count equals the expected value (typically 1).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@rsbuild.config.mjs`:
- Around line 160-162: The WASM deletion hook in the loop that iterates over
Object.keys(compilation.assets) uses a broad regex pattern to delete files
matching `/static[\\/]wasm[\\/].*\.module\.wasm$` without verifying the expected
cardinality. Add a cardinality assertion before or after the deletion loop to
verify that exactly one WASM file matches the pattern, ensuring that if multiple
WASM sources are added in the future, the hook will fail safely rather than
silently deleting unexpected assets. This can be done by counting the matches
against the regex pattern and asserting that the count equals the expected value
(typically 1).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8c59b386-6cf7-455e-bfd1-e33e14b732f8

📥 Commits

Reviewing files that changed from the base of the PR and between bb252b9 and 52a494c.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (4)
  • package.json
  • rsbuild.config.mjs
  • src/modules/views/Pdf/PdfEditor.jsx
  • src/modules/views/Pdf/pdfAssets.js

The Pdfium engine and glyph fallback run inside a blob: Web Worker
whose base URL is the blob itself, so the root-relative
`/static/pdfium.wasm` could not be resolved there ("Failed to parse
URL") and the editor hung forever on "Initializing plugins". Anchor the
asset URLs to window.location.origin so they resolve in the worker as
well as on the main thread.

@codescene-delta-analysis codescene-delta-analysis Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gates Passed
3 Quality Gates Passed

See analysis details in CodeScene

Quality Gate Profile: The Bare Minimum
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@Crash--

Crash-- commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

You can test with this branch, it works git://github.com/cozy/cozy-drive.git#build-qv-210626

@Crash-- Crash-- added the e2e Run the E2E suite on this PR label Jun 21, 2026
@Crash-- Crash-- merged commit da942b4 into master Jun 22, 2026
8 checks passed
@Crash-- Crash-- deleted the fix/pdf-self-host-embedpdf-assets branch June 22, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

e2e Run the E2E suite on this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants