Audit and optimise React component performance + optimize JS bundle - #783
Open
abhijitb wants to merge 12 commits into
Open
Audit and optimise React component performance + optimize JS bundle#783abhijitb wants to merge 12 commits into
abhijitb wants to merge 12 commits into
Conversation
- Lazy-load all pages except Home via React.lazy + Suspense, splitting them into on-demand chunks (index.js 211KB -> 154KB) - Lazy-load the NewfoldNotifications vendor component - Remove top-level awaits in routes.js: marketplace subnav is now fetched via a useMarketplaceSubnavRoutes hook instead of blocking module evaluation, and the performance feature condition reads window.NewfoldFeatures.features synchronously - Fix webpack-public-path.js: the exported function was never called and read NewfoldRuntime.url (site URL) instead of NewfoldRuntime.plugin.url (versioned build URL); now sets __webpack_public_path__ at import time so chunks resolve correctly - Fix ErrorBoundary FallbackComponent being passed an element instead of a component - Fix start:analyzer flag forwarding and add build:analyzer script
- Drop the react-use dependency: only useUpdateEffect was used, now a ~15-line local hook in App/util/hooks consumed by the six settings components - Stop scanning minified vendor build bundles in tailwind.config.js content globs; those modules (onboarding, ecommerce, next-steps, performance) enqueue their own compiled CSS, and scanning minified code makes Tailwind emit utilities for class-like strings. Scan module src/ and assets/js/ sources instead. All 10 utility classes dropped by this change are duplicated in the owning module's own CSS.
The sass-loader shipped with @wordpress/scripts 27 (v12) still calls Dart Sass through the legacy JS API, so every .scss file logs a deprecation warning. Modern API support needs sass-loader 14+, which we only get when wp-scripts upgrades. Until then, pass silenceDeprecations: ['legacy-js-api'] to sass via the merged config.
- Split boot/error status into a dedicated AppBootContext so AppBody (and everything it renders) no longer re-renders every time a settings component writes to the app store - Memoize the NotificationFeed context value with a stable push callback so pushing/dismissing a snackbar doesn't re-render every useNotification() consumer - Remove the duplicate NewfoldNotifications instance that TopBarNav rendered inside an always-hidden div; it fired a second notifications API request on every page load for UI that could never be seen - Use functional setStore in the boot effect to avoid a stale closure
- Memoize TopBarNav's nav-links array with useMemo (was documented as done but wasn't actually implemented) - Wrap AutomaticUpdates.toggleAutoUpdatesAll in useCallback (same gap) - Verify TopBarNav/MobileNav's setIsOpen(false)-on-navigation effects are already no-ops when already closed; no debounce needed - Reinstate react-use (removed earlier for dependency hygiene) since the upcoming @newfold/ui-component-library upgrade requires it as a dependency anyway; drop the local useUpdateEffect hook in favor of react-use's version across the six settings pages that used it
Replace the TBD placeholders with actual measured before/after/final numbers from the current build (build/2.3.4). Notes that "After Splitting" duplicates "Before" since route-level code splitting was already present in the Jul 16 baseline build, so this table isolates the impact of the memoization/lodash/context work done this session: +24 KB (+16%) on index.js, no change to index.css.
react-use was reinstated last commit on the assumption that @newfold/ui-component-library's latest release requires it. Checked the actual published package on npm (1.3.0 and 2.1.1, the version bumped to in #588) — neither declares or uses react-use. With no dependency forcing it in, and confirmed ~0 KB bundle impact either way (Settings chunk was byte-identical with and without it), removed it again and restored the local useUpdateEffect hook. Also tested and documented two other bundle-size questions: - Merging PR #588 (UI-library 1.3.0 -> 2.1.1): regresses index.js by +25 KB and total JS by +71 KB, mostly from the @headlessui/react v1 -> v2 bump. Its lodash dependency is unchanged between versions, so it doesn't address the size problem this branch already flagged. Recommend not merging for size reasons. - Dropping our explicit `lodash` dependency in favor of the UI library's transitive one: confirmed 0 byte saving via `npm ls lodash` (already a single deduped copy). Kept it explicit rather than accept a phantom-dependency risk for no size benefit.
React DevTools Profiler's panel isn't scriptable from this session's browser-automation tooling, so re-render counts were measured directly instead: temporary console.log instrumentation on AppBody and the six settings-section components, built once from the branch's base commit (via a throwaway git worktree) and once from this branch, same Coming-Soon-toggle interaction against both in the browser. Result: one toggle caused 9 unrelated re-renders before this branch's work, 4 after (-56%) -- AppBody's unrelated re-render eliminated entirely (context-churn fix), the four settings-section components each dropped from 2 renders to 1 (context-stabilization fix removed the double-fire, but each still re-renders once because those six components aren't wrapped in React.memo -- flagged as a separate, still-open follow-up rather than claimed as fixed here). No source files changed; this is a docs-only update recording the methodology and results.
The Phase 1.2 re-render measurement found that four unrelated settings sections still re-rendered once per Coming Soon toggle even after the context-stabilization fixes, because none of the six top-level settings components (ComingSoon, AutomaticUpdates, WonderBlockSettings, ContentSettings, CommentSettings, PerformanceFeatureSettings) were memoized -- so their unmemoized parent (the Settings page, itself a Context consumer of AppStore) re-rendering was enough to re-render them regardless of their own props being unchanged. All six take zero props, so React.memo is a safe, correct fix with no edge cases to worry about. Verified with the same before/after console-instrumentation method used for the original measurement: AutomaticUpdates, ContentSettings, and CommentSettings drop from 1 re-render to 0 per unrelated settings write. WonderBlockSettings stays at 1 -- it (and ComingSoon, PerformanceFeatureSettings) call useContext(AppStore) directly at their own top level, and React.memo cannot prevent a component's own direct context subscription from re-rendering it. Eliminating that one would require splitting AppStore into narrower per-domain contexts, a materially bigger and riskier change left as a follow-up rather than attempted here. Net result measured end to end: one Coming Soon toggle now causes 1 unrelated re-render, down from 9 before this branch's work (-89%).
AI code review✅ Strengths
❌ Issues (blocking)
|
ramyakrishnai
approved these changes
Aug 7, 2026
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.
Proposed changes
Started as a bundle-size effort; net result is bundle size grew slightly (index.js +24 KB), but re-renders and two production-breaking bugs got fixed instead.
Bundle size — investigated, not reduced: the +24 KB comes entirely from @newfold/ui-component-library's bundled lodash, unrelated to anything in this branch. Tested merging #588 (#588) (UI library 1.3.0→2.1.1) as a fix — it makes size worse (+25 KB more, new 56.7 KB chunk from a @headlessui/react v2 bump) — recommend not merging it for size reasons. Also audited lodash/react-use/html-react-parser dependency changes; none yield real savings. Full data in docs/react-performance-optimisation-plan.md.
Type of Change
Production
Development
Visual
Checklist
Further comments