build: emit and publish JS source maps for Sentry symbolication#554
Draft
dcalhoun wants to merge 8 commits into
Draft
build: emit and publish JS source maps for Sentry symbolication#554dcalhoun wants to merge 8 commits into
dcalhoun wants to merge 8 commits into
Conversation
Enable Vite `build.sourcemap: 'hidden'` so the production build emits `.map` files (for later upload to Sentry) without shipping a `//# sourceMappingURL=` comment in the bundle. Strip `*.map` from the iOS and Android native bundles in `copy-dist-ios`/`copy-dist-android` so maps never ship inside the app — they'd bloat the binary and expose de-minified source — while `dist/` retains them for the delivery/upload step. Groundwork for Sentry source-map symbolication of editor exceptions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In the `build-react` CI step, package Vite's emitted `.map` files into `GutenbergKitSourceMaps.zip` (preserving the `assets/` layout), then strip the maps from `dist/` before creating `dist.tar.gz`. Stripping here keeps the maps out of every app bundle even for downstream steps (e.g. the Android publish) that copy `dist/` directly rather than through the map-stripping Makefile targets. Upload the zip to `gutenbergkit/<version>/GutenbergKitSourceMaps.zip` from `publish_to_s3`, alongside the XCFramework. The maps ship as a separate S3 object rather than inside the XCFramework because SwiftPM binary-target consumers don't surface sibling files to the host build; host apps fetch the zip by GutenbergKit version and upload it to Sentry for exception symbolication. Publishing is optional end to end: the artifact downloads tolerate a missing zip and `publish_to_s3` skips the upload when it's absent. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
XCFramework BuildThis PR's XCFramework is available for testing. Add the following to your .package(url: "https://github.com/wordpress-mobile/GutenbergKit", branch: "pr-build/554")Built from c2507ee |
The PR XCFramework publish path (`publish-pr-xcframework.sh` → `publish_pr_xcframework`) also calls `publish_to_s3`, but didn't download the source-map artifact, so it logged "skipping source-map upload." Download the zip here as well so PR builds publish their maps under `gutenbergkit/pr-builds/<PR#>/`, consistent with the release and per-commit paths. The download tolerates a missing artifact. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
TEMPORARY — do not merge. Throws an unhandled exception on editor load so a host build can confirm the uploaded source maps de-minify the resulting Sentry event. Revert before merging this PR. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add `@sentry/cli` as a dev dependency and run `sentry-cli sourcemaps inject` during `make build`, between the Vite build and the native-bundle copies. This stamps a matching Debug ID into both the shipped JS (via a `//# debugId=` comment + `_sentryDebugIds` global) and the source maps that get uploaded to Sentry. Debug IDs let Sentry associate maps with events regardless of the file path in the stack frame. GutenbergKit's editor runs in a WebView loading files from a per-install bundle directory, so the frame paths contain a random per-install UUID and can never match a fixed uploaded-artifact name — path-based matching cannot work. Debug IDs are the reliable alternative. `sentry-cli` is a build-time dev dependency only; nothing Sentry ships in the bundle. `inject` needs no auth token (uploading stays host-side), and the UUIDs are content-hashed, so builds stay reproducible. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Read the `window._sentryDebugIds` global (populated by the `sentry-cli sourcemaps inject` build step) and emit a `debug_images` array on the exception payload, pairing each stack file with its Debug ID. Reuses the existing stack parsers to resolve which Debug ID belongs to which file. The native bridge forwards this to the crash-logging SDK, which sets it as `debug_meta` on the Sentry event so uploaded source maps match by Debug ID — the reliable path for the editor's unstable WebView file paths. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a `debugImages` property (and a `DebugImage` struct pairing `codeFile` with `debugID`) to `GutenbergJSException`, decoded from the `debug_images` payload the editor now sends. The field is optional — payloads from builds without Debug IDs decode to an empty list — so nothing regresses. The host forwards these to the crash-logging SDK, which attaches them as `debug_meta` on the Sentry event for source-map symbolication. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sentry's Debug ID symbolication needs the minified `.js` alongside its `.map`; uploading only maps produced `js_no_source` / `missing_source` and left frames unsymbolicated. Package both file types (they share the same injected Debug ID) so Sentry can apply the map to the minified source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What?
Generate JavaScript source maps during the production build and publish them to
S3 so host apps can upload them to Sentry.
This is the GutenbergKit-side (Phase A) of a cross-repo effort. It produces
and delivers the maps; a follow-up in WordPress-iOS will fetch and upload
them to Sentry during its own release build. Symbolication doesn't take effect
until that host-side lane lands.
Why?
GutenbergKit editor exceptions currently appear in Sentry with minified,
unreadable frames (e.g.
editor-CZ39QhNu.js:1:326003, seeJETPACK-IOS-1KAQ), making them
hard to triage. GutenbergKit produces the JS, but the host apps publish the
exceptions to Sentry — so GutenbergKit needs to emit source maps and hand them
to the host.
The approach mirrors the existing, proven
gutenberg-mobile→ host pipeline:classic release/dist matching, with the host app performing the upload during
its own signed build. No Sentry SDK changes and no debug IDs.
How?
vite.config.js: enablebuild.sourcemap: 'hidden'— emits.mapfileswithout a
//# sourceMappingURL=comment in the shipped JS (the maps arestripped from the bundles, so such a comment would dangle). Dev-server
debugging is unaffected;
build.sourcemapapplies only to production builds.Makefile: strip*.mapfrom the iOS/Android native bundles incopy-dist-ios/copy-dist-android, so maps never ship inside the app (they'dbloat the binary and expose de-minified source) while
dist/keeps them fordelivery.
.buildkite/pipeline.yml: inbuild-react, package the maps intoGutenbergKitSourceMaps.zip(preserving theassets/layout), then stripmaps from
dist/beforedist.tar.gz— keeping every downstream consumer(including the Android publish, which copies
dist/directly) map-free.fastlane/Fastfile+.buildkite/release.sh: upload the zip togutenbergkit/<version>/GutenbergKitSourceMaps.zipfrompublish_to_s3,alongside the XCFramework. Maps ship as a separate S3 object because SwiftPM
binary-target consumers don't surface sibling files to the host build.
Publishing is optional end to end: artifact downloads tolerate a missing zip
and
publish_to_s3skips the upload when it's absent.Testing Instructions
make build REFRESH_JS_BUILD=1.find dist -name '*.map'lists.mapfiles.find ios/Sources/GutenbergKitResources/Gutenberg android/Gutenberg/src/main/assets -name '*.map'returns nothing.
//# sourceMappingURL=comment(the only hits are the third-party
wordpress-globals/vips-workerfiles).build-reactstep uploads aGutenbergKitSourceMaps.zipartifact and that
dist.tar.gzcontains no.mapfiles.Accessibility Testing Instructions
N/A — build tooling only; no UI changes.