Jenkins Warnings: Bundle Size Investigation & Support

by SLV Team 54 views

🚨 Jenkins Warnings: Bundle Size Investigation & Support

🚨 Jenkins Warnings: Bundle Size Investigation & Support

📋 Context

For several weeks, our Jenkins CI/CD pipeline has been consistently reporting warnings related to the JavaScript bundle size generated during production builds. These warnings clutter the Jenkins logs and create confusion regarding the quality of the delivered code. We've identified that this issue doesn't stem from our application code but from the external libraries and dependencies we use, in accordance with the company's development standards.

Image

⚠️ Observed Symptoms

Jenkins Warning

Each production build triggers the following warning:

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets: 
  9999.awt_cpv_builder.js (1.95 MiB)
  1550.awt_cpv_builder.js (277 KiB)
  2000.awt_cpv_builder.js (320 KiB)

Technical Details

  • Problematic Bundle: 9999.awt_cpv_builder.js
  • Uncompressed Size: 1.95 MB
  • Estimated Gzipped Size: ~577 KB
  • Recommended Limit: 244 KB (360 KB gzipped)
  • Exceedance: +217 KB gzipped (or +60% over the limit)

Impact

  • ❌ Systematic warnings in Jenkins for several weeks
  • ❌ Confusion among development and code review teams
  • ❌ Difficulty identifying actual issues in CI/CD logs
  • No user impact - The bundle functions correctly in production

🔍 Investigation by the Development Team

1️⃣ Applied Optimizations

✅ Babel Configuration - Smart Polyfills

Modified file: modules/front-js/babel.config.js

// Configuration added to import only the necessary polyfills
{
  modules: false,
  useBuiltIns: 'usage',  // ← Optimization
  corejs: 3,             // ← Optimization
  targets: { browsers: [...] }
}

Result: Reduced size by ~50 KB by avoiding the complete import of core-js.


✅ Removal of Redundant Manual Imports

Modified file: modules/front-js/ts/App.tsx

Removed 8 lines of manual imports for core-js and regenerator-runtime, now managed automatically by Babel.

Result: Cleaner code and reduced size.


✅ Lazy Loading with webpackChunkName

Modified file: modules/front-js/ts/navigation/LazyRoutes.ts

Added webpackChunkName to 17 lazy-loaded components to optimize code splitting:

// Before
lazy(() => import('../features/octavia/pages/OctaviaRecherchePage'))

// After
lazy(() => import(
  /* webpackChunkName: "page-recherche" */
  '../features/octavia/pages/OctaviaRecherchePage'
))

Optimized Pages: page-recherche, page-dossiers, page-financement, page-analyse, page-decision, page-engagement, page-roe, page-garantie, page-intervenant, page-detail-intervenant, page-gestion, page-exemple-home, page-exemple-version, page-accessibilite, page-utilisateur-non-autorise, page-alert, wrapped-routes.

Result: Improved chunk identification and preparation for future optimizations.


✅ Tree Shaking and Minification

  • Configuration usedExports: true activated
  • TerserPlugin for JavaScript minification
  • Specific imports from submodules (@avenir/components/sg-card)
  • Context replacement for moment.js (French locale only)

2️⃣ Webpack Configuration Attempts

We tested 6 different splitChunks configurations to try and reduce the size of bundle 9999:

  1. ❌ splitChunks configuration with maxSize: 350000
  2. ❌ Separating vendors into distinct cacheGroups (React, Redux, Avenir, AWT)
  3. ❌ Configuration enforce: true on cacheGroups
  4. ❌ Complete deactivation of splitChunks (splitChunks: false)
  5. ❌ Complete replacement of prodConfig.optimization
  6. ❌ Webpack configuration without inheriting from prodConfig

Result: None of these configurations changed the size of bundle 9999.


3️⃣ Bundle Composition Analysis

We thoroughly analyzed the composition of bundle 9999.awt_cpv_builder.js:

Composition of bundle 9999 (1.95 MB unzipped, ~577 KB gzipped)
├─ @avenir/components : ~200 KB gzipped (34.6%)
├─ @avenir/core       : ~50 KB gzipped (8.7%)
├─ react + react-dom  : ~130 KB gzipped (22.5%)
├─ redux + redux-saga : ~20 KB gzipped (3.5%)
├─ react-router       : ~50 KB gzipped (8.7%)
├─ awt-* libraries    : ~50 KB gzipped (8.7%)
│  ├─ awt-bootstraper
│  ├─ awt-gda-loader
│  ├─ awt-natif
│  ├─ awt-react-extras
│  └─ awt-common-log
└─ Utilities        : ~77 KB gzipped (13.3%)
   ├─ axios
   ├─ formik
   ├─ yup
   └─ date-fns

Total : ~577 KB gzipped

🎯 Diagnosis: Root Cause Identified

Bundle 9999 is a Shared Vendors Chunk

Bundle 9999.awt_cpv_builder.js is not a bug, but the expected result of webpack's code splitting strategy:

  1. Automatic Detection: Webpack detects that React, Redux, Avenir Components, etc., are used by all 17 lazy-loaded pages.
  2. Extraction into a Common Chunk: To optimize browser caching and avoid duplication, webpack extracts these vendors into a single chunk (bundle 9999).
  3. Performance Trade-off: This optimizes caching but creates a large initial file.

Why the Optimizations Didn't Work

The optimizations we applied (polyfills, tree shaking, lazy loading) reduce application code but not the external vendors, which represent 87% of the bundle.

Bundle 9999 is composed of:

  • 87% external libraries: @avenir, React, Redux, AWT, etc.
  • 13% application code: Already optimized

🛠️ What We CANNOT Solve on the Development Side

1. Size of Avenir Libraries

Components from @avenir/components (200 KB gzipped) and @avenir/core (50 KB gzipped) represent 43% of the bundle.

Why this is problematic:

  • We only use the necessary components via specific imports.
  • Tree shaking is active but limited by the library's architecture.
  • We cannot modify the source code of @avenir.

Possible actions only by Avenir maintainers:

  • More granular module splitting.
  • Bundle size optimization of each component.
  • Better tree shaking support.
  • Documentation of the heaviest components.

2. Imposed AWT Webpack Configuration

We use the webpack configuration provided by awt-webpack-config@5.3.2, which imposes:

const prodConfig = require('awt-webpack-config/lib/webpack.prod.config.js');

Why this is problematic:

  • The prodConfig configuration automatically generates the 9999 vendors bundle.
  • We cannot modify this logic without stepping outside the AWT framework.
  • Attempts to override the configuration had no effect.

Possible actions only by AWT maintainers:

  • Provide an option to customize splitChunks.
  • Document the expected size limits.
  • Provide optimized alternative configurations.

3. Required Framework Dependencies

The XBlocks AWT v7 architecture requires the use of:

  • React 18.3.1 (~130 KB gzipped)
  • Redux + Redux-Saga (~20 KB gzipped)
  • React Router 6.29.0 (~50 KB gzipped)
  • AWT libraries (~50 KB gzipped)

Total required dependencies: ~250 KB gzipped (or 43% of the bundle)

These dependencies are necessary to comply with the framework and cannot be replaced or reduced without going outside the imposed development framework.


📊 Concrete Evidence

Webpack Bundle Analyzer Analysis

We generated a visual report with webpack-bundle-analyzer:

cd modules/front-js
pnpm analyze

Results:

  • Bundle 9999 contains 1252 modules from node_modules.
  • The 5 heaviest libraries represent 70% of the bundle:
    1. @avenir/components: 34.6%
    2. react + react-dom: 22.5%
    3. Other utilities: 13.3%
    4. react-router: 8.7%
    5. @avenir/core: 8.7%

Complete Webpack Logs

orphan modules 7.18 MiB [orphan] 3109 modules
runtime modules 7.71 KiB 13 modules
cacheable modules 8.52 MiB (javascript) 2.7 MiB (asset)
  modules by path ./node_modules/.pnpm/ 6.92 MiB (javascript) 2.7 MiB (asset)
    javascript modules 6.92 MiB 914 modules
  modules by path ./ts/ 1.6 MiB 101 modules

WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
Assets: 
  9999.awt_cpv_builder.js (1.95 MiB)

Observation: The application code (./ts/) represents only 18.7% of the total, while node_modules represents 81.3%.


🙏 Request for Support from Maintainers

To the Avenir Team (@avenir/components, @avenir/core)

Problem: Avenir components represent 43% of our vendors bundle (250 KB gzipped).

Questions:

  1. Is there a roadmap to reduce the size of the components?
  2. Are there any components we use that are particularly heavy?
  3. Is it possible to improve tree shaking to reduce unused imports?

Documentation used:

  • Specific imports: from '@avenir/components/sg-card'
  • No global import: from '@avenir/components'

Request:

  • Audit the size of Avenir components in our project.
  • Recommendations to reduce the bundle size.

To the AWT Team (awt-webpack-config, awt-bootstraper)

Problem: The imposed webpack configuration generates a vendors bundle of 577 KB gzipped with a limit of 360 KB.

Questions:

  1. What is the recommended bundle size limit for an AWT v7 application?
  2. Is it possible to customize the splitChunks configuration without breaking AWT compatibility?
  3. Are there AWT applications that respect the 360 KB limit for vendors?

Current Configuration:

const prodConfig = require('awt-webpack-config/lib/webpack.prod.config.js');

Request:

  • Documentation of best practices to reduce AWT bundle sizes.
  • Configuration option to divide the vendors bundle into multiple chunks.
  • Clarification on acceptable size limits.

To the XBlocks Framework Team

Problem: The required framework dependencies (React, Redux, Router, AWT libs) represent 250 KB gzipped (43% of the bundle).

Questions:

  1. Is there a roadmap to reduce the required dependencies?
  2. Is it possible to externalize some libraries (React, Redux) via CDN?
  3. What are the recommendations for applications with many lazy-loaded pages?

Request:

  • Audit of our architecture to validate that we are following best practices.
  • Specific recommendations to reduce the vendors bundle size.

📈 Impact and Urgency

Current Impact

  • ⚠️ Medium: Systematic warnings in Jenkins for several weeks
  • ⚠️ Medium: Confusion within the development teams
  • No user impact: The application functions correctly in production

Urgency

  • 🔴 Medium: The problem affects the readability of CI/CD pipelines
  • 🟠 Short term: We need to clarify if this is a real problem or a false positive
  • 🟢 Long term: Improve the architecture to meet the limits

💡 Proposed Solutions

Option 1: Accept the Trade-off (Recommended in the short term)

Proposition: Accept that the 577 KB gzipped vendors bundle is an acceptable compromise for our architecture.

Justification:

  • The bundle contains all vendors for the entire application.
  • It is loaded only once and cached.
  • Individual pages are small (< 100 KB).
  • Overall performance is better than with duplication.

Action:

  • Document this exception in the Jenkins configuration.
  • Disable the warning specifically for the 9999 bundle.
  • Monitor the size evolution.

Option 2: Architecture Refactoring (Long term)

Proposition: Refactor the architecture to create multiple entry points instead of a single vendors bundle.

Approach:

  1. "Core" bundle with React/Redux/Router (~200 KB)
  2. "avenir-ui" bundle with Avenir components (~200 KB)
  3. "features" bundle per business domain (~100 KB each)

Option 3: Collaboration with Maintainers (Preferred)

Proposition: Work with the Avenir and AWT teams to identify optimizations in the source libraries.

Benefit:

  • Improvement for all projects using these libraries.
  • No modification of our architecture.
  • Sustainable solution.

Steps:

  1. Joint audit of the bundle composition.
  2. Identification of optimizable components/libraries.
  3. Implementation of optimizations in the source libraries.
  4. Update of our dependencies.