Skip to content

Conversation

@mshriver
Copy link
Contributor

@mshriver mshriver commented Dec 17, 2025

Unfortunate tradeoff here where we see build time warnings for css import order issues due to code splitting and patternfly-styles use. They're just warnings though, and we end up with smaller bundle with split files.

Test coverage is being modified here and I'll not include any updates to tests in this PR:
#792

Before

$ ./bin/write-version-file.cjs && DISABLE_ESLINT_PLUGIN=true react-scripts build
Creating an optimized production build...
Compiled successfully.

File sizes after gzip:

  568.14 kB  build/static/js/main.648c38ea.js
  397.88 kB  build/static/js/764.00784904.chunk.js
  118.52 kB  build/static/css/main.c59ff3da.css

The bundle size is significantly larger than recommended.

After

File sizes after gzip:

  397.88 kB  build/static/js/9764.d25440da.chunk.js
  154.53 kB  build/static/js/244.74bbf18e.chunk.js
  91.43 kB   build/static/js/3400.d15e03d7.chunk.js
  85.94 kB   build/static/js/main.1fb9ff00.js
  51.28 kB   build/static/js/2589.6de1437c.chunk.js
  35.88 kB   build/static/css/2589.848af298.chunk.css
  34.53 kB   build/static/css/main.93263e88.css
  31.99 kB   build/static/js/1005.312c23d9.chunk.js
  23.34 kB   build/static/js/1732.7be64347.chunk.js
  21.59 kB   build/static/js/6407.500557c6.chunk.js
  20.03 kB   build/static/js/3519.1ca28c8d.chunk.js
  18.77 kB   build/static/js/5895.940433db.chunk.js
  15.05 kB   build/static/css/3519.e5a8d859.chunk.css
  13.01 kB   build/static/js/2857.5646fe8d.chunk.js
  12.62 kB   build/static/js/6992.7c9b40d4.chunk.js
  10.59 kB   build/static/js/4489.3a8f8b52.chunk.js
  9.69 kB    build/static/js/1071.a5a17bf8.chunk.js
  8.68 kB    build/static/js/5528.e3b36e97.chunk.js
  8.49 kB    build/static/js/2991.dda0256c.chunk.js
  8.46 kB    build/static/js/4748.b6657763.chunk.js
  7.71 kB    build/static/js/5838.5b2d494c.chunk.js
  7.38 kB    build/static/css/1005.253cfd12.chunk.css
  7.12 kB    build/static/js/6788.c28f4b05.chunk.js
  7.06 kB    build/static/js/2085.34b5e78b.chunk.js
  6.04 kB    build/static/css/2857.32852e5a.chunk.css
  5.9 kB     build/static/js/3923.39796df8.chunk.js
  5.79 kB    build/static/js/3252.e109ea1f.chunk.js
  5.71 kB    build/static/js/5646.15c822e9.chunk.js
  5.43 kB    build/static/js/1953.4968c1b0.chunk.js
  5.33 kB    build/static/js/8801.0e7ca954.chunk.js
  5.07 kB    build/static/js/9697.1659180f.chunk.js
  5.03 kB    build/static/js/3759.930d6486.chunk.js
  4.52 kB    build/static/js/5333.07ba3938.chunk.js
  4.08 kB    build/static/js/6931.5af4623b.chunk.js
  4.01 kB    build/static/js/4318.e8a9ff1a.chunk.js
  3.72 kB    build/static/js/4346.fe536cc2.chunk.js
  3.69 kB    build/static/css/1071.be6e9804.chunk.css
  3.68 kB    build/static/js/192.f47cb4a9.chunk.js
  3.62 kB    build/static/css/8295.f26ea8c0.chunk.css
  3.6 kB     build/static/js/2997.e28123b7.chunk.js
  3.53 kB    build/static/js/7186.0401fc8f.chunk.js
  3.47 kB    build/static/css/9216.9b06e837.chunk.css
  3.4 kB     build/static/css/7330.34213381.chunk.css
  3.28 kB    build/static/js/6477.885483d1.chunk.js
  3.24 kB    build/static/css/6992.96685ce5.chunk.css
  3.23 kB    build/static/js/9816.08a1151b.chunk.js
  3.15 kB    build/static/css/6099.58f099e9.chunk.css
  3.04 kB    build/static/js/5470.603580ea.chunk.js
  2.87 kB    build/static/js/4533.5ce435ff.chunk.js
  2.65 kB    build/static/js/5174.0da02482.chunk.js
  2.61 kB    build/static/css/4098.0e96234d.chunk.css
  2.54 kB    build/static/css/1440.dfd5a9b1.chunk.css
  2.44 kB    build/static/js/3100.56df51a0.chunk.js
  2.43 kB    build/static/css/4383.69775a1d.chunk.css
  2.37 kB    build/static/js/5548.fe642064.chunk.js
  2.34 kB    build/static/js/3561.c8c0445a.chunk.js
  2.28 kB    build/static/js/8139.8057d548.chunk.js
  2.2 kB     build/static/js/803.7779f4d1.chunk.js
  2.07 kB    build/static/css/6349.cd11d98c.chunk.css
  1.92 kB    build/static/js/7025.4ea49da5.chunk.js
  1.76 kB    build/static/css/2997.4fa76034.chunk.css
  1.76 kB    build/static/css/8801.4fa76034.chunk.css
  1.71 kB    build/static/css/1612.4c8983bf.chunk.css
  1.33 kB    build/static/css/5895.f629434b.chunk.css
  1.22 kB    build/static/js/6349.a8461453.chunk.js
  1.09 kB    build/static/js/4808.def45145.chunk.js
  1.02 kB    build/static/css/5174.46855aab.chunk.css
  713 B      build/static/css/3923.868e31f2.chunk.css
  564 B      build/static/css/6931.1e26d2be.chunk.css

Copilot AI review requested due to automatic review settings December 17, 2025 14:35
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Dec 17, 2025

Reviewer's Guide

Frontend bundle size optimizations via React lazy-loading, route and widget code-splitting, icon tree-shaking imports, Docker/runtime tweaks, and documentation updates for building images and running the frontend.

Sequence diagram for lazy-loaded dashboard route

sequenceDiagram
  actor User
  participant BrowserRouter
  participant SuspenseRoute
  participant DashboardChunk as Dashboard_module
  participant Server

  User->>BrowserRouter: Navigate to /project/:project_id/dashboard
  BrowserRouter->>SuspenseRoute: Render Dashboard element
  SuspenseRoute->>DashboardChunk: dynamic import('../pages/dashboard')
  DashboardChunk->>Server: HTTP GET dashboard.chunk.js
  Server-->>DashboardChunk: dashboard.chunk.js
  DashboardChunk-->>SuspenseRoute: Promise resolved with Dashboard
  Note over SuspenseRoute: While pending, render PageSpinner/ContentSpinner
  SuspenseRoute-->>BrowserRouter: Render Dashboard component
  BrowserRouter-->>User: Dashboard UI displayed
Loading

Sequence diagram for lazy-loaded Jenkins heatmap widget

sequenceDiagram
  actor User
  participant DashboardPage
  participant useWidgetsHook
  participant JenkinsHeatmapWrapper
  participant getHeatmapTypes
  participant FilterHeatmapWidget
  participant FilterHeatmapModule as filter_heatmap_module

  User->>DashboardPage: Open dashboard with jenkins-heatmap widget
  DashboardPage->>useWidgetsHook: Render widgets
  useWidgetsHook->>JenkinsHeatmapWrapper: Render widget component
  JenkinsHeatmapWrapper->>JenkinsHeatmapWrapper: useEffect on mount
  JenkinsHeatmapWrapper->>getHeatmapTypes: getHeatmapTypes()
  getHeatmapTypes->>FilterHeatmapModule: import('../../widgets/filter-heatmap')
  FilterHeatmapModule-->>getHeatmapTypes: HEATMAP_TYPES
  getHeatmapTypes-->>JenkinsHeatmapWrapper: types.jenkins
  JenkinsHeatmapWrapper->>JenkinsHeatmapWrapper: setHeatmapType(types.jenkins)
  Note over JenkinsHeatmapWrapper: While heatmapType is null, render WidgetSpinner
  JenkinsHeatmapWrapper->>FilterHeatmapWidget: Render with title, params, type, callbacks
  FilterHeatmapWidget-->>User: Jenkins heatmap displayed
Loading

File-Level Changes

Change Details Files
Implement widget and route-level React lazy loading and Suspense-based loading states for code splitting.
  • Refactor widgets hook to lazy-load widget components (heatmaps, charts, importance component) using React.lazy and Suspense.
  • Introduce JenkinsHeatmapWrapper to asynchronously resolve HEATMAP_TYPES with a small cache and show a spinner until loaded.
  • Add reusable WidgetSpinner, PageSpinner, and ContentSpinner components to provide centered loading indicators for widgets, pages, and admin/project content.
  • Wrap route/page components in Suspense fallbacks in Base, App, and Admin routes to split bundles per route and nested content.
frontend/src/components/hooks/use-widgets.js
frontend/src/routes/base.js
frontend/src/routes/app.js
frontend/src/routes/admin.js
Optimize PatternFly icons imports for better tree-shaking and smaller bundles.
  • Replace grouped icon imports from '@patternfly/react-icons' with direct ESM icon imports from '@patternfly/react-icons/dist/esm/icons/*'.
  • Update all affected components (constants, filter UI, modals, widgets, tables, admin pages, etc.) to use the new import style.
frontend/src/constants.js
frontend/src/pages/admin/user-list.js
frontend/src/components/widget-header.js
frontend/src/components/filtering/active-filters.js
frontend/src/components/modals/new-dashboard-modal.js
frontend/src/components/multi-value-input.js
frontend/src/components/empty-object.js
frontend/src/components/filtering/result-filter.js
frontend/src/components/hooks/use-table-filters.js
frontend/src/components/modals/edit-widget-modal.js
frontend/src/components/result-view.js
frontend/src/components/table-states.js
frontend/src/components/user-dropdown.js
frontend/src/pages/admin/project-edit.js
frontend/src/pages/admin/project-list.js
frontend/src/pages/admin/user-edit.js
frontend/src/pages/login.js
frontend/src/pages/reset-password.js
frontend/src/pages/run.js
frontend/src/pages/sign-up.js
frontend/src/pages/user-profile.js
frontend/src/pages/user-tokens.js
frontend/src/routes/ibutsu-page.js
frontend/src/utilities/tables.js
frontend/src/views/accessibility-analysis.js
frontend/src/views/jenkins-job.js
frontend/src/widgets/filter-heatmap.js
Add Docker build and runtime wiring for the frontend and document container build workflows.
  • Add a Docker entrypoint script that generates a settings.js file in the built frontend based on environment variables, allowing runtime configuration of server URL and environment.
  • Introduce a frontend Dockerfile (Dockerfile.frontend) wired to use the new entrypoint and build artifacts.
  • Document backend and frontend container build commands in AGENTS.md using podman and branch-tagged images.
frontend/docker/entrypoint.sh
frontend/docker/Dockerfile.frontend
AGENTS.md
Adjust frontend package metadata and dev/start configuration to align with containerized runtime.
  • Set a human-readable description field in frontend/package.json.
  • Change the serve port for the built app from 3000 to 8080 to better match container defaults.
  • Update the devserver script to explicitly set PORT=3000 while running react-scripts start so development and production ports differ predictably.
frontend/package.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In use-widgets.js, you're dynamically importing ../../widgets/filter-heatmap twice (once for FilterHeatmapWidget and once for HEATMAP_TYPES_PROMISE); consider centralizing this into a single dynamic import (e.g., a helper that exposes both the default widget and HEATMAP_TYPES) to avoid duplicate chunks and keep the exports in sync.
  • There are multiple very similar inline spinner components (WidgetSpinner, PageSpinner, ContentSpinner) with minor style differences; consider extracting a shared loading/spinner component to reduce duplication and keep the loading UX consistent.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `use-widgets.js`, you're dynamically importing `../../widgets/filter-heatmap` twice (once for `FilterHeatmapWidget` and once for `HEATMAP_TYPES_PROMISE`); consider centralizing this into a single dynamic import (e.g., a helper that exposes both the default widget and `HEATMAP_TYPES`) to avoid duplicate chunks and keep the exports in sync.
- There are multiple very similar inline spinner components (`WidgetSpinner`, `PageSpinner`, `ContentSpinner`) with minor style differences; consider extracting a shared loading/spinner component to reduce duplication and keep the loading UX consistent.

## Individual Comments

### Comment 1
<location> `frontend/src/components/hooks/use-widgets.js:23-22` </location>
<code_context>
+    default: module.FilterHeatmapWidget,
+  })),
+);
+const HEATMAP_TYPES_PROMISE = import('../../widgets/filter-heatmap').then(
+  (module) => module.HEATMAP_TYPES,
+);
+
+const GenericAreaWidget = lazy(() => import('../../widgets/generic-area'));
</code_context>

<issue_to_address>
**suggestion (performance):** Defer creating the HEATMAP_TYPES import promise to avoid an eager side-effect at module load time.

`HEATMAP_TYPES_PROMISE` is created when the module is loaded, so the dynamic import runs even if `JenkinsHeatmapWrapper` is never rendered. To keep this truly lazy, move the import into `getHeatmapTypes` and cache the result there, for example:

```js
let heatmapTypesPromise;
let heatmapTypesCache = null;

const getHeatmapTypes = async () => {
  if (heatmapTypesCache) return heatmapTypesCache;
  if (!heatmapTypesPromise) {
    heatmapTypesPromise = import('../../widgets/filter-heatmap')
      .then(m => m.HEATMAP_TYPES);
  }
  heatmapTypesCache = await heatmapTypesPromise;
  return heatmapTypesCache;
};
```

This way the chunk only loads when needed and is reused on subsequent calls.

Suggested implementation:

```javascript
const FilterHeatmapWidget = lazy(() =>
  import('../../widgets/filter-heatmap').then((module) => ({
    default: module.FilterHeatmapWidget,
  })),
);

let heatmapTypesPromise;
let heatmapTypesCache = null;

const getHeatmapTypes = async () => {
  if (heatmapTypesCache) return heatmapTypesCache;
  if (!heatmapTypesPromise) {
    heatmapTypesPromise = import('../../widgets/filter-heatmap').then(
      (module) => module.HEATMAP_TYPES,
    );
  }
  heatmapTypesCache = await heatmapTypesPromise;
  return heatmapTypesCache;
};

const GenericAreaWidget = lazy(() => import('../../widgets/generic-area'));

```

1. Replace any existing uses of `HEATMAP_TYPES_PROMISE` in this file (or its consumers) with calls to `getHeatmapTypes()`. For example:
   - `await HEATMAP_TYPES_PROMISE``await getHeatmapTypes()`.
2. If `HEATMAP_TYPES_PROMISE` was being exported from this module, remove that export and export `getHeatmapTypes` instead, preserving the existing export style (named or default).
</issue_to_address>

### Comment 2
<location> `frontend/docker/entrypoint.sh:10-13` </location>
<code_context>
+
+echo "Generating settings.js with runtime configuration..."
+
+cat > /opt/app-root/src/build/settings.js << EOF
+window.settings = {};
+window.settings.serverUrl='${REACT_APP_SERVER_URL:-http://localhost:8080/api}';
+window.settings.environment='${NODE_ENV:-development}';
+EOF
+
</code_context>

<issue_to_address>
**🚨 issue (security):** Escape environment variable values when embedding them into JavaScript strings.

`REACT_APP_SERVER_URL` and `NODE_ENV` are inserted directly into single-quoted JS strings. If they contain characters like `'`, `\`, or newlines, `settings.js` may become invalid, and in some cases misconfigured values could lead to code injection. Please escape these values before writing them, e.g. via JSON encoding:

```bash
cat > /opt/app-root/src/build/settings.js << EOF
window.settings = {};
window.settings.serverUrl=$(printf '%s' "${REACT_APP_SERVER_URL:-http://localhost:8080/api}" | jq -Rs .);
window.settings.environment=$(printf '%s' "${NODE_ENV:-development}" | jq -Rs .);
EOF
```

JSON-encoding avoids most escaping issues and makes the script more robust to unexpected env values.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements bundle size optimization for the frontend through code splitting and tree-shaking optimizations. The changes address the issue of a large bundle size (568.14 kB main JS after gzip) by implementing lazy loading for routes and widgets, and switching from barrel imports to direct ESM imports for PatternFly React icons.

  • Replaced barrel imports for PatternFly icons with direct ESM imports to enable tree-shaking
  • Implemented lazy loading with React.lazy() and Suspense for route-level components
  • Added code splitting for widget components in the dashboard system
  • Updated Docker configuration to use Node.js 20 base images and simplified deployment
  • Aligned port configuration across package.json, Docker, and deployment scripts

Reviewed changes

Copilot reviewed 35 out of 35 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
frontend/src/widgets/filter-heatmap.js Converted icon imports from barrel to direct ESM imports
frontend/src/views/jenkins-job.js Converted icon imports from barrel to direct ESM imports
frontend/src/views/accessibility-analysis.js Converted icon imports from barrel to direct ESM imports
frontend/src/utilities/tables.js Converted icon imports from barrel to direct ESM imports
frontend/src/routes/ibutsu-page.js Converted icon imports from barrel to direct ESM imports
frontend/src/routes/base.js Added lazy loading for top-level routes with Suspense boundaries and loading spinner
frontend/src/routes/app.js Added lazy loading for page components with per-route Suspense boundaries
frontend/src/routes/admin.js Added lazy loading for admin page components with Suspense boundaries
frontend/src/pages/user-tokens.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/user-profile.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/sign-up.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/run.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/reset-password.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/login.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/admin/user-list.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/admin/user-edit.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/admin/project-list.js Converted icon imports from barrel to direct ESM imports
frontend/src/pages/admin/project-edit.js Converted icon imports from barrel to direct ESM imports
frontend/src/constants.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/widget-header.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/user-dropdown.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/table-states.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/result-view.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/multi-value-input.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/modals/new-dashboard-modal.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/modals/edit-widget-modal.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/hooks/use-widgets.js Added lazy loading for widget components with custom async handling for HEATMAP_TYPES
frontend/src/components/hooks/use-table-filters.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/filtering/result-filter.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/filtering/active-filters.js Converted icon imports from barrel to direct ESM imports
frontend/src/components/empty-object.js Converted icon imports from barrel to direct ESM imports
frontend/package.json Changed production server port from 3000 to 8080, added PORT=3000 to devserver script, added description field
frontend/docker/entrypoint.sh New entrypoint script for runtime configuration of React app via settings.js
frontend/docker/Dockerfile.frontend Migrated from nginx-based deployment to Node.js serve, updated to UBI9 Node.js 20 images, simplified build process
AGENTS.md Added documentation for building container images with podman

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@codecov
Copy link

codecov bot commented Dec 17, 2025

Codecov Report

❌ Patch coverage is 0% with 77 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.95%. Comparing base (a49b1e4) to head (7f22cb3).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
frontend/src/components/hooks/use-widgets.js 0.00% 49 Missing ⚠️
frontend/src/components/loading-spinners.js 0.00% 9 Missing ⚠️
frontend/src/routes/base.js 0.00% 8 Missing ⚠️
frontend/src/routes/app.js 0.00% 6 Missing ⚠️
frontend/src/routes/admin.js 0.00% 5 Missing ⚠️

❌ Your patch status has failed because the patch coverage (0.00%) is below the target coverage (85.00%). You can increase the patch coverage or adjust the target coverage.
❌ Your project status has failed because the head coverage (63.95%) is below the target coverage (85.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #795      +/-   ##
==========================================
- Coverage   64.47%   63.95%   -0.52%     
==========================================
  Files         156      157       +1     
  Lines        7572     7633      +61     
  Branches      659      659              
==========================================
  Hits         4882     4882              
- Misses       2456     2517      +61     
  Partials      234      234              
Files with missing lines Coverage Δ
frontend/src/components/empty-object.js 100.00% <ø> (ø)
...rontend/src/components/filtering/active-filters.js 100.00% <ø> (ø)
frontend/src/components/filtering/result-filter.js 50.00% <ø> (ø)
frontend/src/components/hooks/use-table-filters.js 43.16% <ø> (ø)
...rontend/src/components/modals/edit-widget-modal.js 100.00% <ø> (ø)
...ntend/src/components/modals/new-dashboard-modal.js 100.00% <ø> (ø)
frontend/src/components/multi-value-input.js 29.41% <ø> (ø)
frontend/src/components/result-view.js 98.14% <ø> (ø)
frontend/src/components/table-states.js 100.00% <ø> (ø)
frontend/src/components/user-dropdown.js 0.00% <ø> (ø)
... and 21 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a49b1e4...7f22cb3. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

lazy route imports
direct icon imports

suppress css import warnings from patternfly-styles that come from code
splitting with CI=false in container build
@mshriver mshriver force-pushed the frontend-bundle-size branch from 486651a to 511d996 Compare December 17, 2025 15:09
@mshriver mshriver merged commit 0d3a733 into ibutsu:main Dec 17, 2025
13 of 15 checks passed
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.

1 participant