Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Bundle optimization - analiza i optymalizacja pakietów

Bundle optimization to kompleksowy proces analizy i optymalizacji pakietów JavaScript, mający na celu maksymalne zmniejszenie rozmiaru, poprawę wydajności ładowania oraz efektywne wykorzystanie zasobów przeglądarki. To ostatni krok w procesie optymalizacji aplikacji webowych - gdy mamy już code splitting, tree shaking i lazy loading, przychodzi czas na głęboką analizę i fine-tuning całego bundle.

Dlaczego bundle optimization jest kluczowy?

Wpływ na Core Web Vitals

1// Metryki wydajności przed optymalizacją
2const beforeOptimization = {
3  bundleSize: '2.8MB',
4  firstContentfulPaint: '3.4s',
5  largestContentfulPaint: '5.1s',
6  timeToInteractive: '6.2s',
7  cumulativeLayoutShift: 0.25
8};
9
10// Metryki wydajności po optymalizacji
11const afterOptimization = {
12  bundleSize: '420KB',
13  firstContentfulPaint: '0.9s',
14  largestContentfulPaint: '1.6s',
15  timeToInteractive: '2.1s',
16  cumulativeLayoutShift: 0.05
17};
18
19// Poprawa wydajności
20const improvement = {
21  bundleSizeReduction: '85%',
22  fcpImprovement: '73%',
23  lcpImprovement: '69%',
24  ttiImprovement: '66%',
25  clsImprovement: '80%'
26};

Koszty biznesowe nieoptymalizowanych bundli

1// Analiza kosztów business impact
2const businessImpact = {
3  conversionRate: {
4    before: '2.1%',
5    after: '3.8%',
6    improvement: '+81%'
7  },
8  bounceRate: {
9    before: '68%',
10    after: '42%',
11    improvement: '-38%'
12  },
13  mobileUsersLost: {
14    before: '35%', // Przez wolne ładowanie
15    after: '12%',
16    improvement: '-66%'
17  },
18  revenueImpact: {
19    monthlyLoss: '$24,000', // Z powodu wolnych bundli
20    monthlyGain: '$45,000'  // Po optymalizacji
21  }
22};

Narzędzia do analizy bundli

1. Webpack Bundle Analyzer

1# Instalacja i użycie
2npm install --save-dev webpack-bundle-analyzer
3
4# Generowanie raportu
5npx webpack-bundle-analyzer dist/static/js/*.js
6
7# Integracja z webpack config
8const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
9
10module.exports = {
11  plugins: [
12    new BundleAnalyzerPlugin({
13      analyzerMode: 'static',
14      openAnalyzer: false,
15      generateStatsFile: true,
16      reportFilename: 'bundle-report.html'
17    })
18  ]
19};

2. Bundle Size Analysis z CI/CD

1# .github/workflows/bundle-analysis.yml
2name: Bundle Analysis
3on: [push, pull_request]
4
5jobs:
6  analyze:
7    runs-on: ubuntu-latest
8    steps:
9      - uses: actions/checkout@v2
10      
11      - name: Setup Node.js
12        uses: actions/setup-node@v2
13        with:
14          node-version: '18'
15          
16      - name: Install dependencies
17        run: npm ci
18        
19      - name: Build and analyze
20        run: |
21          npm run build
22          npx bundlesize
23          
24      - name: Upload bundle stats
25        uses: actions/upload-artifact@v2
26        with:
27          name: bundle-stats
28          path: dist/bundle-stats.json

3. Source Map Explorer

1# Analiza source map
2npm install --global source-map-explorer
3
4# Analiza konkretnego bundle
5source-map-explorer bundle.js bundle.js.map
6
7# Porównanie dwóch wersji
8source-map-explorer bundle.js --compare-to=bundle-old.js

4. Webpack Dashboard

1// Interaktywny dashboard podczas development
2const DashboardPlugin = require('webpack-dashboard/plugin');
3
4module.exports = {
5  plugins: [
6    new DashboardPlugin()
7  ]
8};

Zaawansowane techniki optymalizacji

1. Dynamic chunking strategies

1// webpack.config.js - Zaawansowana konfiguracja chunks
2module.exports = {
3  optimization: {
4    splitChunks: {
5      chunks: 'all',
6      minSize: 20000,
7      maxSize: 244000,
8      cacheGroups: {
9        // Framework chunks (React, Angular, Vue)
10        framework: {
11          test: /[\/]node_modules[\/](react|react-dom|@angular|vue)[\/]/,
12          name: 'framework',
13          priority: 40,
14          enforce: true
15        },
16        
17        // UI Libraries chunk
18        ui: {
19          test: /[\/]node_modules[\/](@mui|antd|bootstrap|@chakra-ui)[\/]/,
20          name: 'ui-libs',
21          priority: 30,
22          enforce: true
23        },
24        
25        // Utility libraries chunk
26        utils: {
27          test: /[\/]node_modules[\/](lodash|ramda|date-fns|moment)[\/]/,
28          name: 'utils',
29          priority: 20,
30          enforce: true
31        },
32        
33        // Common application code
34        common: {
35          name: 'common',
36          minChunks: 2,
37          priority: 10,
38          reuseExistingChunk: true
39        },
40        
41        // Large libraries w osobnych chunkach
42        largeDeps: {
43          test: /[\/]node_modules[\/](monaco-editor|three|d3)[\/]/,
44          name(module) {
45            const packageName = module.context.match(/[\/]node_modules[\/](.*?)([\/]|$)/)[1];
46            return `lib.${packageName.replace('@', '')}`;
47          },
48          priority: 35,
49          enforce: true
50        }
51      }
52    }
53  }
54};

2. Module Federation dla mikrofrontendów

1// webpack.config.js - Host application
2const ModuleFederationPlugin = require('@module-federation/webpack');
3
4module.exports = {
5  plugins: [
6    new ModuleFederationPlugin({
7      name: 'host',
8      filename: 'remoteEntry.js',
9      remotes: {
10        userDashboard: 'userDashboard@http://localhost:3001/remoteEntry.js',
11        productCatalog: 'productCatalog@http://localhost:3002/remoteEntry.js',
12        paymentSystem: 'paymentSystem@http://localhost:3003/remoteEntry.js'
13      },
14      shared: {
15        react: {
16          singleton: true,
17          requiredVersion: '^18.0.0',
18          eager: true
19        },
20        'react-dom': {
21          singleton: true,
22          requiredVersion: '^18.0.0',
23          eager: true
24        }
25      }
26    })
27  ]
28};
29
30// Micro-frontend - User Dashboard
31const ModuleFederationPlugin = require('@module-federation/webpack');
32
33module.exports = {
34  plugins: [
35    new ModuleFederationPlugin({
36      name: 'userDashboard',
37      filename: 'remoteEntry.js',
38      exposes: {
39        './UserProfile': './src/components/UserProfile',
40        './UserSettings': './src/components/UserSettings'
41      },
42      shared: {
43        react: { singleton: true },
44        'react-dom': { singleton: true }
45      }
46    })
47  ]
48};

3. Incremental bundling

1// Webpack cache configuration dla szybszych rebuildów
2module.exports = {
3  cache: {
4    type: 'filesystem',
5    cacheDirectory: path.resolve(__dirname, '.webpack-cache'),
6    buildDependencies: {
7      config: [__filename],
8      tsconfig: [path.resolve(__dirname, 'tsconfig.json')],
9      packagejson: [path.resolve(__dirname, 'package.json')]
10    },
11    version: '1.0',
12    store: 'pack',
13    compression: 'gzip'
14  },
15  
16  // Persistent cache dla node_modules
17  snapshot: {
18    managedPaths: [path.resolve(__dirname, 'node_modules')],
19    buildDependencies: {
20      hash: true,
21      timestamp: true
22    },
23    module: {
24      timestamp: true
25    },
26    resolve: {
27      timestamp: true
28    }
29  }
30};

Performance budgets i monitoring

1. Performance budgets configuration

1// bundlesize configuration w package.json
2{
3  "bundlesize": [
4    {
5      "path": "./dist/js/main.*.js",
6      "maxSize": "170 kB",
7      "compression": "gzip"
8    },
9    {
10      "path": "./dist/js/vendor.*.js",
11      "maxSize": "300 kB",
12      "compression": "gzip"
13    },
14    {
15      "path": "./dist/css/*.css",
16      "maxSize": "50 kB",
17      "compression": "gzip"
18    },
19    {
20      "path": "./dist/js/runtime.*.js",
21      "maxSize": "10 kB",
22      "compression": "gzip"
23    }
24  ]
25}

2. Automated performance monitoring

1// Performance monitoring service
2class BundlePerformanceMonitor {
3  constructor() {
4    this.metrics = {
5      bundleSizes: new Map(),
6      loadTimes: new Map(),
7      cacheHitRates: new Map()
8    };
9    
10    this.thresholds = {
11      maxBundleSize: 250000, // 250KB
12      maxLoadTime: 3000,     // 3s
13      minCacheHitRate: 80    // 80%
14    };
15  }
16  
17  async measureBundlePerformance() {
18    const performanceData = {
19      timestamp: Date.now(),
20      metrics: await this.collectMetrics(),
21      violations: this.checkViolations(),
22      recommendations: this.generateRecommendations()
23    };
24    
25    await this.sendToMonitoring(performanceData);
26    return performanceData;
27  }
28  
29  async collectMetrics() {
30    const bundleEntries = performance.getEntriesByType('navigation');
31    const resourceEntries = performance.getEntriesByType('resource');
32    
33    return {
34      pageLoadTime: bundleEntries[0]?.loadEventEnd - bundleEntries[0]?.fetchStart,
35      resourceLoadTimes: resourceEntries
36        .filter(entry => entry.name.includes('.js') || entry.name.includes('.css'))
37        .map(entry => ({
38          name: entry.name,
39          size: entry.transferSize,
40          loadTime: entry.responseEnd - entry.fetchStart,
41          cached: entry.transferSize === 0
42        })),
43      memoryUsage: performance.memory ? {
44        used: performance.memory.usedJSHeapSize,
45        total: performance.memory.totalJSHeapSize,
46        limit: performance.memory.jsHeapSizeLimit
47      } : null
48    };
49  }
50  
51  checkViolations() {
52    const violations = [];
53    
54    // Sprawdzenie rozmiarów bundli
55    this.metrics.bundleSizes.forEach((size, bundleName) => {
56      if (size > this.thresholds.maxBundleSize) {
57        violations.push({
58          type: 'SIZE_VIOLATION',
59          bundle: bundleName,
60          current: size,
61          threshold: this.thresholds.maxBundleSize,
62          severity: 'HIGH'
63        });
64      }
65    });
66    
67    return violations;
68  }
69  
70  generateRecommendations() {
71    const recommendations = [];
72    
73    // Analiza duplikatów w bundlach
74    const duplicatedModules = this.findDuplicatedModules();
75    if (duplicatedModules.length > 0) {
76      recommendations.push({
77        type: 'REMOVE_DUPLICATES',
78        modules: duplicatedModules,
79        estimatedSavings: this.calculateDuplicateSavings(duplicatedModules)
80      });
81    }
82    
83    // Analiza nieużywanych dependencji
84    const unusedDeps = this.findUnusedDependencies();
85    if (unusedDeps.length > 0) {
86      recommendations.push({
87        type: 'REMOVE_UNUSED_DEPS',
88        dependencies: unusedDeps,
89        estimatedSavings: this.calculateUnusedDepsSavings(unusedDeps)
90      });
91    }
92    
93    return recommendations;
94  }
95}
96
97// Automatyczne monitorowanie w production
98if (typeof window !== 'undefined' && process.env.NODE_ENV === 'production') {
99  const monitor = new BundlePerformanceMonitor();
100  
101  // Pomiar po załadowaniu strony
102  window.addEventListener('load', () => {
103    setTimeout(() => {
104      monitor.measureBundlePerformance();
105    }, 2000);
106  });
107}

3. Real User Monitoring (RUM)

1// RUM dla bundle performance
2class RealUserBundleMonitoring {
3  constructor() {
4    this.sessionId = this.generateSessionId();
5    this.startTime = performance.now();
6    this.setupObservers();
7  }
8  
9  setupObservers() {
10    // Performance Observer dla resource timing
11    if ('PerformanceObserver' in window) {
12      const observer = new PerformanceObserver((list) => {
13        list.getEntries().forEach(entry => {
14          if (entry.name.includes('.js') || entry.name.includes('.css')) {
15            this.trackResourceLoad(entry);
16          }
17        });
18      });
19      
20      observer.observe({ entryTypes: ['resource'] });
21    }
22    
23    // Long task observer
24    if ('PerformanceObserver' in window) {
25      const longTaskObserver = new PerformanceObserver((list) => {
26        list.getEntries().forEach(entry => {
27          this.trackLongTask(entry);
28        });
29      });
30      
31      longTaskObserver.observe({ entryTypes: ['longtask'] });
32    }
33  }
34  
35  trackResourceLoad(entry) {
36    const resourceData = {
37      sessionId: this.sessionId,
38      timestamp: Date.now(),
39      resourceType: entry.name.includes('.js') ? 'javascript' : 'css',
40      resourceName: entry.name,
41      loadTime: entry.responseEnd - entry.fetchStart,
42      transferSize: entry.transferSize,
43      cached: entry.transferSize === 0,
44      userAgent: navigator.userAgent,
45      connectionType: navigator.connection?.effectiveType
46    };
47    
48    this.sendMetric('resource_load', resourceData);
49  }
50  
51  trackLongTask(entry) {
52    const longTaskData = {
53      sessionId: this.sessionId,
54      timestamp: Date.now(),
55      duration: entry.duration,
56      startTime: entry.startTime,
57      attribution: entry.attribution
58    };
59    
60    this.sendMetric('long_task', longTaskData);
61  }
62  
63  async sendMetric(type, data) {
64    // Wysyłanie do systemu analytics
65    if (navigator.sendBeacon) {
66      navigator.sendBeacon('/api/metrics', JSON.stringify({
67        type,
68        data,
69        metadata: {
70          url: window.location.href,
71          timestamp: Date.now(),
72          sessionId: this.sessionId
73        }
74      }));
75    }
76  }
77}

Optymalizacja specyficznych bibliotek

1. Lodash optimization

1# Analiza użycia Lodash
2npx lodash-cli modularize exports=node
3
4# Babel plugin dla automatycznej optymalizacji
5npm install --save-dev babel-plugin-lodash
1// babel.config.js
2module.exports = {
3  plugins: [
4    'lodash' // Automatycznie zamienia importy na cherry-picked
5  ]
6};
7
8// Przed optymalizacją (70KB)
9import _ from 'lodash';
10
11// Po optymalizacji (2KB)
12import debounce from 'lodash/debounce';
13import throttle from 'lodash/throttle';

2. Date library optimization

1// Porównanie rozmiarów bibliotek dat
2const dateLibraryComparison = {
3  'moment': {
4    size: '230KB',
5    gzipped: '67KB',
6    treeshaking: false
7  },
8  'date-fns': {
9    size: '78KB',
10    gzipped: '13KB',
11    treeshaking: true
12  },
13  'dayjs': {
14    size: '9KB',
15    gzipped: '3KB',
16    treeshaking: true
17  },
18  'luxon': {
19    size: '67KB',
20    gzipped: '19KB',
21    treeshaking: true
22  }
23};
24
25// Migration guide z Moment.js do date-fns
26const migrationExamples = {
27  before: `
28    import moment from 'moment';
29    
30    const formatted = moment().format('DD/MM/YYYY');
31    const isAfter = moment(date1).isAfter(date2);
32  `,
33  after: `
34    import { format, isAfter } from 'date-fns';
35    import { pl } from 'date-fns/locale';
36    
37    const formatted = format(new Date(), 'dd/MM/yyyy', { locale: pl });
38    const isAfterResult = isAfter(date1, date2);
39  `
40};

3. CSS framework optimization

1// PurgeCSS dla usuwania nieużywanych styli
2const purgecss = require('@fullhuman/postcss-purgecss');
3
4module.exports = {
5  plugins: [
6    purgecss({
7      content: [
8        './src/**/*.html',
9        './src/**/*.js',
10        './src/**/*.tsx'
11      ],
12      safelist: [
13        /^tooltip-/,
14        /^modal-/,
15        /^dropdown-/
16      ],
17      defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
18    })
19  ]
20};
21
22// Bundle size reduction examples
23const cssOptimizationResults = {
24  bootstrap: {
25    before: '150KB',
26    after: '23KB',
27    reduction: '85%'
28  },
29  tailwind: {
30    before: '3.2MB',
31    after: '12KB',
32    reduction: '99.6%'
33  },
34  materialUI: {
35    before: '890KB',
36    after: '145KB',
37    reduction: '84%'
38  }
39};

Zaawansowane webpack optimization

1. Custom webpack plugins

1// Plugin do analizy i optymalizacji bundle
2class BundleOptimizationPlugin {
3  constructor(options = {}) {
4    this.options = {
5      reportPath: 'bundle-optimization-report.json',
6      thresholds: {
7        maxChunkSize: 250000,
8        maxModuleSize: 50000
9      },
10      ...options
11    };
12  }
13  
14  apply(compiler) {
15    compiler.hooks.emit.tapAsync('BundleOptimizationPlugin', (compilation, callback) => {
16      const report = this.generateOptimizationReport(compilation);
17      
18      // Zapisz raport
19      compilation.assets[this.options.reportPath] = {
20        source: () => JSON.stringify(report, null, 2),
21        size: () => JSON.stringify(report, null, 2).length
22      };
23      
24      // Loguj ostrzeżenia
25      this.logWarnings(compilation, report);
26      
27      callback();
28    });
29  }
30  
31  generateOptimizationReport(compilation) {
32    const chunks = Array.from(compilation.chunks);
33    const modules = Array.from(compilation.modules);
34    
35    return {
36      timestamp: new Date().toISOString(),
37      summary: {
38        totalChunks: chunks.length,
39        totalModules: modules.length,
40        totalSize: this.calculateTotalSize(chunks)
41      },
42      chunks: chunks.map(chunk => ({
43        id: chunk.id,
44        name: chunk.name,
45        size: chunk.size,
46        modules: chunk.getModules().length,
47        parents: Array.from(chunk.groupsIterable, g => g.getParents()),
48        children: Array.from(chunk.groupsIterable, g => g.getChildren())
49      })),
50      optimizationOpportunities: this.findOptimizationOpportunities(chunks, modules),
51      recommendations: this.generateRecommendations(chunks, modules)
52    };
53  }
54  
55  findOptimizationOpportunities(chunks, modules) {
56    const opportunities = [];
57    
58    // Znajdź duże moduły
59    const largeModules = modules.filter(module => 
60      module.size() > this.options.thresholds.maxModuleSize
61    );
62    
63    if (largeModules.length > 0) {
64      opportunities.push({
65        type: 'LARGE_MODULES',
66        modules: largeModules.map(m => ({
67          identifier: m.identifier(),
68          size: m.size(),
69          reasons: m.reasons.map(r => r.module?.identifier())
70        }))
71      });
72    }
73    
74    // Znajdź duplikaty
75    const moduleDuplicates = this.findModuleDuplicates(modules);
76    if (moduleDuplicates.length > 0) {
77      opportunities.push({
78        type: 'MODULE_DUPLICATES',
79        duplicates: moduleDuplicates
80      });
81    }
82    
83    return opportunities;
84  }
85}
86
87// Użycie plugin
88module.exports = {
89  plugins: [
90    new BundleOptimizationPlugin({
91      thresholds: {
92        maxChunkSize: 200000,
93        maxModuleSize: 30000
94      }
95    })
96  ]
97};

2. Runtime chunk optimization

1// Optymalizacja runtime chunk
2module.exports = {
3  optimization: {
4    runtimeChunk: {
5      name: entrypoint => `runtime-${entrypoint.name}`
6    },
7    
8    // Minimizer configuration
9    minimizer: [
10      new TerserPlugin({
11        parallel: true,
12        terserOptions: {
13          parse: {
14            ecma: 2020
15          },
16          compress: {
17            ecma: 2020,
18            comparisons: false,
19            inline: 2,
20            drop_console: process.env.NODE_ENV === 'production',
21            drop_debugger: process.env.NODE_ENV === 'production',
22            pure_funcs: ['console.log', 'console.info', 'console.debug']
23          },
24          mangle: {
25            safari10: true
26          },
27          output: {
28            ecma: 2020,
29            comments: false,
30            ascii_only: true
31          }
32        }
33      }),
34      
35      new CssMinimizerPlugin({
36        parallel: true,
37        minimizerOptions: {
38          preset: [
39            'default',
40            {
41              discardComments: { removeAll: true },
42              normalizeWhitespace: true,
43              colormin: true,
44              convertValues: true,
45              discardDuplicates: true,
46              discardEmpty: true,
47              mergeRules: true,
48              minifyFontValues: true,
49              minifyGradients: true,
50              minifyParams: true,
51              minifySelectors: true,
52              normalizeCharset: true,
53              normalizeDisplayValues: true,
54              normalizePositions: true,
55              normalizeRepeatStyle: true,
56              normalizeString: true,
57              normalizeTimingFunctions: true,
58              normalizeUnicode: true,
59              normalizeUrl: true,
60              orderedValues: true,
61              reduceIdents: true,
62              reduceInitial: true,
63              reduceTransforms: true,
64              svgo: true,
65              uniqueSelectors: true
66            }
67          ]
68        }
69      })
70    ]
71  }
72};

Bundle testing i validation

1. Automated bundle testing

1// Test suite dla bundle optimization
2const bundleTests = {
3  // Test rozmiaru bundle
4  async testBundleSize() {
5    const bundleStats = await getBundleStats();
6    const maxSize = 500000; // 500KB
7    
8    expect(bundleStats.totalSize).toBeLessThan(maxSize);
9    expect(bundleStats.mainChunk).toBeLessThan(200000);
10    expect(bundleStats.vendorChunk).toBeLessThan(300000);
11  },
12  
13  // Test duplikatów
14  async testNoDuplicateModules() {
15    const bundleAnalysis = await analyzeBundleContent();
16    const duplicates = bundleAnalysis.duplicatedModules;
17    
18    expect(duplicates).toHaveLength(0);
19  },
20  
21  // Test tree shaking effectiveness
22  async testTreeShakingEffectiveness() {
23    const unusedExports = await findUnusedExports();
24    const deadCode = await findDeadCode();
25    
26    expect(unusedExports.length).toBeLessThan(5);
27    expect(deadCode.totalSize).toBeLessThan(10000);
28  },
29  
30  // Test cache effectiveness
31  async testCacheability() {
32    const chunks = await getChunkManifest();
33    
34    chunks.forEach(chunk => {
35      if (chunk.type === 'vendor') {
36        expect(chunk.hash).toMatch(/^[a-f0-9]{8}$/);
37        expect(chunk.cacheable).toBe(true);
38      }
39    });
40  }
41};
42
43// Integration z CI/CD
44describe('Bundle Optimization Tests', () => {
45  test('Bundle size within limits', bundleTests.testBundleSize);
46  test('No duplicate modules', bundleTests.testNoDuplicateModules);
47  test('Tree shaking effective', bundleTests.testTreeShakingEffectiveness);
48  test('Chunks properly cacheable', bundleTests.testCacheability);
49});

2. Performance regression detection

1// System do wykrywania regresji wydajności
2class PerformanceRegressionDetector {
3  constructor() {
4    this.baselineMetrics = null;
5    this.threshold = 0.1; // 10% wzrost = regresja
6  }
7  
8  async setBaseline() {
9    this.baselineMetrics = await this.measureCurrentMetrics();
10    await this.saveBaseline(this.baselineMetrics);
11  }
12  
13  async detectRegressions() {
14    const currentMetrics = await this.measureCurrentMetrics();
15    const regressions = [];
16    
17    if (!this.baselineMetrics) {
18      this.baselineMetrics = await this.loadBaseline();
19    }
20    
21    // Sprawdź rozmiary bundli
22    const sizeRegression = this.detectSizeRegression(
23      this.baselineMetrics.bundleSize,
24      currentMetrics.bundleSize
25    );
26    
27    if (sizeRegression) {
28      regressions.push(sizeRegression);
29    }
30    
31    // Sprawdź czasy ładowania
32    const loadTimeRegression = this.detectLoadTimeRegression(
33      this.baselineMetrics.loadTime,
34      currentMetrics.loadTime
35    );
36    
37    if (loadTimeRegression) {
38      regressions.push(loadTimeRegression);
39    }
40    
41    return regressions;
42  }
43  
44  detectSizeRegression(baseline, current) {
45    const increase = (current - baseline) / baseline;
46    
47    if (increase > this.threshold) {
48      return {
49        type: 'SIZE_REGRESSION',
50        baseline: baseline,
51        current: current,
52        increase: `${(increase * 100).toFixed(1)}%`,
53        severity: increase > 0.25 ? 'HIGH' : 'MEDIUM'
54      };
55    }
56    
57    return null;
58  }
59  
60  async generateRegressionReport(regressions) {
61    return {
62      timestamp: new Date().toISOString(),
63      regressions: regressions,
64      recommendations: await this.generateRecommendations(regressions),
65      actionItems: this.generateActionItems(regressions)
66    };
67  }
68}

Production deployment strategies

1. Progressive deployment

1// Strategia progressive deployment dla bundli
2class ProgressiveBundleDeployment {
3  constructor() {
4    this.deploymentStages = [
5      { name: 'canary', percentage: 5 },
6      { name: 'blue-green', percentage: 50 },
7      { name: 'full', percentage: 100 }
8    ];
9  }
10  
11  async deployNewBundle(bundleVersion) {
12    for (const stage of this.deploymentStages) {
13      console.log(`Deploying to ${stage.name} (${stage.percentage}% traffic)`);
14      
15      await this.deployToStage(bundleVersion, stage);
16      
17      const metrics = await this.monitorStageMetrics(stage, 300000); // 5 min
18      
19      if (!this.validateStageSuccess(metrics)) {
20        await this.rollbackStage(stage);
21        throw new Error(`Deployment failed at ${stage.name} stage`);
22      }
23      
24      console.log(`Stage ${stage.name} successful`);
25    }
26  }
27  
28  async monitorStageMetrics(stage, duration) {
29    const startTime = Date.now();
30    const metrics = {
31      errorRate: [],
32      loadTimes: [],
33      bundleErrors: []
34    };
35    
36    while (Date.now() - startTime < duration) {
37      const sample = await this.collectMetricsSample(stage);
38      metrics.errorRate.push(sample.errorRate);
39      metrics.loadTimes.push(sample.avgLoadTime);
40      metrics.bundleErrors.push(sample.bundleErrors);
41      
42      await new Promise(resolve => setTimeout(resolve, 30000)); // 30s intervals
43    }
44    
45    return metrics;
46  }
47  
48  validateStageSuccess(metrics) {
49    const avgErrorRate = metrics.errorRate.reduce((a, b) => a + b) / metrics.errorRate.length;
50    const avgLoadTime = metrics.loadTimes.reduce((a, b) => a + b) / metrics.loadTimes.length;
51    const totalBundleErrors = metrics.bundleErrors.reduce((a, b) => a + b);
52    
53    return avgErrorRate < 0.01 && // < 1% error rate
54           avgLoadTime < 3000 &&  // < 3s load time
55           totalBundleErrors < 5; // < 5 bundle errors
56  }
57}

2. A/B testing dla bundle optimization

1// A/B testing różnych strategii bundle optimization
2class BundleOptimizationABTest {
3  constructor() {
4    this.variants = {
5      control: {
6        strategy: 'current',
7        splitChunks: 'default',
8        compression: 'gzip'
9      },
10      optimized: {
11        strategy: 'aggressive_splitting',
12        splitChunks: 'custom',
13        compression: 'brotli'
14      },
15      experimental: {
16        strategy: 'module_federation',
17        splitChunks: 'micro_chunks',
18        compression: 'zstd'
19      }
20    };
21  }
22  
23  async runABTest(duration = 7 * 24 * 60 * 60 * 1000) { // 7 days
24    const testId = this.generateTestId();
25    
26    // Rozpocznij test
27    await this.startTest(testId);
28    
29    // Monituj metryki
30    const results = await this.monitorTest(testId, duration);
31    
32    // Analizuj wyniki
33    const analysis = await this.analyzeResults(results);
34    
35    // Wybierz zwycięzcę
36    const winner = this.selectWinner(analysis);
37    
38    return {
39      testId,
40      duration,
41      results,
42      analysis,
43      winner,
44      recommendation: this.generateRecommendation(analysis, winner)
45    };
46  }
47  
48  async monitorTest(testId, duration) {
49    const results = {
50      control: { metrics: [], samples: 0 },
51      optimized: { metrics: [], samples: 0 },
52      experimental: { metrics: [], samples: 0 }
53    };
54    
55    const startTime = Date.now();
56    
57    while (Date.now() - startTime < duration) {
58      for (const variant of Object.keys(this.variants)) {
59        const metrics = await this.collectVariantMetrics(variant);
60        results[variant].metrics.push(metrics);
61        results[variant].samples++;
62      }
63      
64      await new Promise(resolve => setTimeout(resolve, 3600000)); // 1 hour
65    }
66    
67    return results;
68  }
69  
70  selectWinner(analysis) {
71    const scores = {};
72    
73    for (const variant of Object.keys(analysis)) {
74      const data = analysis[variant];
75      
76      scores[variant] = (
77        (1 / data.avgLoadTime) * 0.4 +     // 40% weight
78        (1 / data.avgBundleSize) * 0.3 +   // 30% weight
79        data.conversionRate * 0.2 +        // 20% weight
80        (1 - data.errorRate) * 0.1         // 10% weight
81      );
82    }
83    
84    return Object.keys(scores).reduce((a, b) => 
85      scores[a] > scores[b] ? a : b
86    );
87  }
88}

Podsumowanie i checklist

Bundle Optimization Checklist

1const bundleOptimizationChecklist = {
2  analysis: [
3    '✓ Webpack Bundle Analyzer setup',
4    '✓ Source map analysis',
5    '✓ Performance budget configured',
6    '✓ CI/CD bundle size monitoring',
7    '✓ Duplicate detection'
8  ],
9  
10  codeOptimization: [
11    '✓ Tree shaking enabled',
12    '✓ Dead code elimination',
13    '✓ Unused dependencies removed',
14    '✓ Code splitting implemented',
15    '✓ Lazy loading configured'
16  ],
17  
18  bundleStrategy: [
19    '✓ Chunk splitting optimized',
20    '✓ Vendor chunks separated',
21    '✓ Runtime chunk extracted',
22    '✓ Common chunks identified',
23    '✓ Dynamic imports utilized'
24  ],
25  
26  compression: [
27    '✓ Gzip/Brotli enabled',
28    '✓ Minification configured',
29    '✓ CSS optimization',
30    '✓ Image optimization',
31    '✓ Font optimization'
32  ],
33  
34  caching: [
35    '✓ Long-term caching setup',
36    '✓ Content-based hashing',
37    '✓ Cache invalidation strategy',
38    '✓ Service worker implemented',
39    '✓ CDN optimization'
40  ],
41  
42  monitoring: [
43    '✓ Real user monitoring',
44    '✓ Performance metrics tracking',
45    '✓ Regression detection',
46    '✓ A/B testing capability',
47    '✓ Alert system configured'
48  ]
49};
50
51// ROI calculation
52const optimizationROI = {
53  investment: {
54    developmentTime: '2-3 weeks',
55    toolingSetup: '$5,000',
56    ongoingMaintenance: '$2,000/month'
57  },
58  
59  returns: {
60    conversionRateIncrease: '+25-40%',
61    bounceRateDecrease: '-30-50%',
62    serverCostReduction: '-20-30%',
63    mobileUserRetention: '+35-60%',
64    seoRankingImprovement: '+15-25%'
65  },
66  
67  businessImpact: {
68    revenueIncrease: '$50,000-150,000/year',
69    costSavings: '$20,000-40,000/year',
70    paybackPeriod: '2-4 months',
71    totalROI: '400-800%'
72  }
73};

Bundle optimization to inwestycja, która zwraca się bardzo szybko poprzez poprawę wszystkich kluczowych metryk biznesowych. Systematyczne podejście, ciągły monitoring i iteracyjne ulepszenia pozwalają osiągnąć i utrzymać optymalną wydajność aplikacji.

Przejdź do CodeWorlds