Skip to content

Make QuickPlot work fully client-side without a MapGuide Server#1644

Draft
Copilot wants to merge 5 commits into
masterfrom
copilot/make-quickplot-client-side
Draft

Make QuickPlot work fully client-side without a MapGuide Server#1644
Copilot wants to merge 5 commits into
masterfrom
copilot/make-quickplot-client-side

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 5, 2026

QuickPlot previously required a Fusion server-side PHP endpoint (PlotAsPDF.php) to generate PDFs. This adds a fully client-side mode that uses viewer.exportImage() and jspdf to generate PDFs in-browser, matching the approach already used by the Print command.

Activation

Set ClientSide: "true" in the QuickPlot widget's Extension in the appdef:

{
  "Type": "QuickPlot",
  "Name": "QuickPlot",
  "Extension": [{ "ClientSide": ["true"] }]
}

Changes

  • src/api/mapguide-commands.ts: When the widget extension has ClientSide: "true", the component URL becomes component://QuickPlot?clientSide=true, propagating the flag as a prop to the rendered component.

  • src/containers/quick-plot.tsx:

    • Accepts new optional clientSide?: string prop (via IQuickPlotContainerOwnProps)
    • In client-side mode: relaxes the RuntimeMap guard (no MapGuide session required), renders the Generate button as type="button", and on click: calls viewer.exportImage() → dynamically imports jspdf (webpack code-split boundary) → builds a PDF with the configured paper size/orientation and optional title/subtitle → triggers browser download as quickplot.pdf
    • Server-specific hidden inputs (sessionId, mapName) are omitted in client-side mode
    • Uses /* webpackChunkName: "jspdf" */ magic comment so the async chunk is identifiable in the output
  • src/strings/: Added QUICKPLOT_GENERATING i18n key for the in-progress button label.

  • webpack.config.js:

    • Added compilerOptions: { module: "esnext", moduleResolution: "node" } to the ts-loader rule so that import("jspdf") is preserved as a native dynamic import (TypeScript's module: "commonjs" default would otherwise downlevel it to require(), which webpack cannot code-split).
    • Changed splitChunks.cacheGroups.commons.chunks from "all" to "initial" so the vendor bundle only collects synchronously-loaded node_modules; dynamically-imported modules such as jspdf remain in their own async-only chunk.
  • test/containers/neo-and-quick-plot.spec.tsx: Added vi.mock("jspdf", ...) for the dynamic import; two new tests covering client-side render-without-map and the full exportImage → PDF save flow.

Bundle impact

Bundle Before After
vendor.js 1.85 MiB 1.4 MiB
viewer.js 592 KiB 460 KiB
jspdf chunk n/a 350 KiB async-only, loaded on-demand

Copilot AI changed the title [WIP] Make QuickPlot not require a MapGuide Server Make QuickPlot work fully client-side without a MapGuide Server May 5, 2026
Copilot AI requested a review from jumpinjackie May 5, 2026 16:35
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 6, 2026

Bundle Size Report ✅ PASS

Metric Size Gzip Brotli
Total 12.36 MB 2.81 MB 2.04 MB
Diff +2.16 MB 🔴 ↑ +535.72 KB 🔴 ↑ +416.77 KB 🔴 ↑
Change +21.19% +22.91% +24.99%

Top Changes

File Before After Diff
~ vendor-debug.js 940.95 KB 1.16 MB +251.87 KB 🔴 ↑
~ vendor.js 385.47 KB 548.74 KB +163.28 KB 🔴 ↑
~ viewer-debug.js 200.83 KB 201.80 KB +995.00 B 🔴 ↑
~ viewer.js 122.73 KB 123.39 KB +678.00 B 🔴 ↑

Generated by build-size-diff Commit: 858d87f

@coveralls
Copy link
Copy Markdown

Coverage Status

coverage: 59.713% (+0.04%) from 59.676% — copilot/make-quickplot-client-side into master

@jumpinjackie
Copy link
Copy Markdown
Owner

@copilot Is code-splitting actually happening? The vendor bundle shot up by 2+ MB when I would've expected a new separate jspdf-only vendor bundle.

…ks=initial in splitChunks

Agent-Logs-Url: https://github.com/jumpinjackie/mapguide-react-layout/sessions/f9c7787b-2fa5-4c54-867d-b065dcd3ae99

Co-authored-by: jumpinjackie <563860+jumpinjackie@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 6, 2026

@copilot Is code-splitting actually happening? The vendor bundle shot up by 2+ MB when I would've expected a new separate jspdf-only vendor bundle.

The code-splitting was not working due to two issues that compounded each other:

  1. TypeScript module: "commonjs" — TypeScript was compiling import("jspdf") to Promise.resolve().then(() => require("jspdf")). webpack doesn't recognize that CommonJS pattern as a code-split boundary, so jspdf was silently absorbed into the synchronous bundle.

  2. splitChunks chunks: "all" — Even after fixing the dynamic import, this setting would have pulled the jspdf async chunk back into the synchronous vendor bundle.

Fix in commit 23057ba:

  • Added compilerOptions: { module: "esnext", moduleResolution: "node" } to the ts-loader rule in webpack.config.js — this overrides the TypeScript module output format for webpack builds only, preserving import() as a real dynamic import that webpack can split.
  • Changed splitChunks.cacheGroups.commons.chunks from "all" to "initial" — vendor bundle only collects synchronously-loaded node_modules; async chunks (like jspdf) stay separate.
  • Added /* webpackChunkName: "jspdf" */ magic comment to name the chunk explicitly.

Result:

Bundle Before After
vendor.js 1.85 MiB 1.4 MiB
viewer.js 592 KiB 460 KiB
384.chunk.js (jspdf) n/a 350 KiB (async, on-demand only)

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • storybook.js.org
    • Triggering command: /usr/local/bin/node /usr/local/bin/node /home/REDACTED/work/mapguide-react-layout/mapguide-react-layout/node_modules/storybook/bin/index.cjs build -c .storybook (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make QuickPlot not require a MapGuide Server

3 participants