Skip to content

Premium Analytics: build the internal ui and data packages as script modules#49574

Merged
nerrad merged 1 commit into
trunkfrom
update/pa-ui-script-module
Jun 12, 2026
Merged

Premium Analytics: build the internal ui and data packages as script modules#49574
nerrad merged 1 commit into
trunkfrom
update/pa-ui-script-module

Conversation

@nerrad

@nerrad nerrad commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Part of the work on analytics changes

Proposed changes

Why

The internal packages/* are currently bundled into every consumer: each route, widget render, and widget metadata bundle that imports one gets its own private copy. That model has three concrete failure modes, two of which we've already hit:

  1. Module-scope state isn't shared across bundles. packages/data exports a module-scope QueryClient and global-error manager. Bundled per consumer, every widget type's render bundle gets its own copy — so as data-driven widget types accumulate, each carries a private cache (identical report requests across types can't dedupe) and "the" error manager fragments per bundle.
  2. Styled code cannot reach style-less build contexts. Bundling resolves internal imports to raw src — including .module.scss. Any build pipeline without style plugins (concretely: the widget metadata build) hard-fails the moment its import graph touches a styled internal package (No loader is configured for ".scss" files). This is what blocks widget attribute editors today.
  3. Duplicate bytes that scale with widget count. A package shared by N consumers ships N times. Tolerable at N=2; not at a dashboard of 25+ widgets.

There's no bundler-config way out of (2): esbuild honors tsconfig.json paths over package.json entry fields, so a bundled internal import always lands in src no matter what module/main point at. The only mechanism that delivers a package's compiled output to consumers is the one @wordpress/* packages already use — register it as a script module and externalize the import.

What

Declare wpScriptModuleExports on packages/ui and packages/data, so each is built once into a registered script module and consumer bundles externalize the import:

  • ui — the module is built from the Phase-1 transpile output, where the CSS-module graph is already compiled via the style runtime, so styled components become consumable from any build context (first consumer: the stacked fields-package PR).
  • data — the QueryClient and error manager become page-wide singletons by construction (one registered module instance, every consumer imports it), and widget metadata modules importing helpers like getDefaultQueryParams shrink from ~31 KB to ~1.5 KB each (the bundled helper/datetime slice externalizes).

Also adds the parent-manifest link: entries these modules' bundles resolve through (datetime, formatters) plus ui for future importers — the resolution mechanism documented in #49189.

Scope note: widgets-toolkit would also benefit (it bundles charts + components into every widget render) but is slated for dissolution, so it's deferred pending that decision. datetime/formatters/routing/icons are small, logic-only, and singleton-free — per-consumer bundling is fine there.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No.

Testing instructions

  • pnpm --filter @automattic/jetpack-premium-analytics build — Phase 2 reports ✔ Bundled ui and ✔ Bundled data; build/modules/{ui,data}/ and the module registry contain the new script modules.
  • pnpm --filter @automattic/jetpack-premium-analytics typecheck — clean.
  • No runtime change on trunk: nothing on trunk imports these packages from built page code yet.
  • Runtime-validated end to end on the experimental widget branch (try/wooa7s-1460-widget-inline-report-params-field), which carries this same config plus consumers:
    • widgets render with data/ui declared as external module dependencies, and modules/data/index.min.js loads once per page;
    • the singleton claim was validated with two different data-driven widget types (average-items-per-order and average-order-value: separate render bundles, same orders report). Test design note: instances bake concrete dates into their attributes at insert time, so both instances must be inserted the same day (identical params) for the hypotheses to separate. With identical params, a hard reload shows exactly 2 proxy/reports/orders requests (one primary + one comparison) serving both widget types — per-bundle clients would fire 4, one pair per type, with nothing deduping across bundles.

@nerrad nerrad self-assigned this Jun 12, 2026
@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack or WordPress.com Site Helper), and enable the update/pa-ui-script-module branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack update/pa-ui-script-module
bin/jetpack-downloader test jetpack-mu-wpcom-plugin update/pa-ui-script-module

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!

Declare wpScriptModuleExports on the internal ui and data packages so
each bundles once into a registered script module, and consumer bundles
externalize the import (the same mechanism that externalizes
@wordpress/* script modules) instead of bundling per-consumer copies.

Per-package rationale:
- ui: styled components (CSS modules) can be delivered to build contexts
  with no style support — the module is built from the Phase-1 transpile
  output, where the scss is already compiled via the style runtime.
- data: its module-scope QueryClient and global-error manager become
  genuine page-wide singletons (shared report cache across widgets
  instead of one cache per consumer bundle), and widget metadata modules
  that import helpers like getDefaultQueryParams stop bundling the data
  package (TanStack Query included) per widget.

Adds the link: deps for the internal packages these modules' bundles
resolve (datetime, formatters) plus ui itself for future importers — the
resolution mechanism documented in #49189. Notably, tsconfig paths route
bundled internal imports to src regardless of package.json entry fields
(esbuild honors tsconfig paths), so wpScriptModuleExports externalization
is the only way to deliver an internal package's compiled build output
to consumers.
@nerrad nerrad force-pushed the update/pa-ui-script-module branch from dcde93f to e6bf2e5 Compare June 12, 2026 03:45
@nerrad nerrad changed the title Premium Analytics: build the internal ui package as a script module Premium Analytics: build the internal ui and data packages as script modules Jun 12, 2026
@jp-launch-control

Copy link
Copy Markdown

Code Coverage Summary

This PR did not change code coverage!

That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷

Full summary · PHP report · JS report

@nerrad nerrad requested a review from chihsuan June 12, 2026 04:56
@nerrad nerrad marked this pull request as ready for review June 12, 2026 04:56

@chihsuan chihsuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks @nerrad Clean change and looks good 👍

Just left one small optional note inline but not a blocker.

Comment thread projects/packages/premium-analytics/package.json
@nerrad nerrad merged commit 6b9c1d0 into trunk Jun 12, 2026
105 of 107 checks passed
@nerrad nerrad deleted the update/pa-ui-script-module branch June 12, 2026 06:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants