docs/adding-cdn-bundle.md
This guide explains how to create a new CDN bundle for the browser package that includes a specific combination of features.
Feature combinations use dot notation:
logs.metrics - Bundle with logs and metricsreplay.logs.metrics - Bundle with replay, logs, and metricstracing.replay.logs - Bundle with tracing, replay, and logstracing.replay.feedback.logs.metrics - Full featured bundleFeature order in bundle names: tracing → replay → feedback → logs → metrics
Given a feature combination, derive these variants:
| Placeholder | Example (replay.logs.metrics) |
|---|---|
{FEATURE_COMBO} | replay.logs.metrics |
{feature_combo} | replay_logs_metrics |
{featureCombo} | replayLogsMetrics |
{Human Readable Features} | Replay, Logs, Metrics |
{Human Readable Feature List} | Replay, Logs, and Metrics |
packages/browser/src/index.bundle.{FEATURE_COMBO}.tsBase structure:
// If bundle includes TRACING, add this at the top:
import { registerSpanErrorInstrumentation } from '@sentry/core';
registerSpanErrorInstrumentation();
// Always export base bundle
export * from './index.bundle.base';
For LOGS (without tracing):
export { logger, consoleLoggingIntegration } from '@sentry/core';
For TRACING:
export {
getActiveSpan,
getRootSpan,
getSpanDescendants,
setMeasurement,
startInactiveSpan,
startNewTrace,
startSpan,
startSpanManual,
withActiveSpan,
} from '@sentry/core';
export {
browserTracingIntegration,
startBrowserTracingNavigationSpan,
startBrowserTracingPageLoadSpan,
} from './tracing/browserTracingIntegration';
export { reportPageLoaded } from './tracing/reportPageLoaded';
export { setActiveSpanInBrowser } from './tracing/setActiveSpan';
For REPLAY:
export { replayIntegration, getReplay } from '@sentry-internal/replay';
For FEEDBACK:
import { feedbackAsyncIntegration } from './feedbackAsync';
export { getFeedback, sendFeedback } from '@sentry-internal/feedback';
export { feedbackAsyncIntegration as feedbackAsyncIntegration, feedbackAsyncIntegration as feedbackIntegration };
For features NOT included, export shims:
import {
browserTracingIntegrationShim, // if NO tracing
feedbackIntegrationShim, // if NO feedback
replayIntegrationShim, // if NO replay
consoleLoggingIntegrationShim, // if NO logs
loggerShim, // if NO logs
} from '@sentry-internal/integration-shims';
// Then export them with proper names:
export { browserTracingIntegrationShim as browserTracingIntegration };
export { feedbackIntegrationShim as feedbackAsyncIntegration, feedbackIntegrationShim as feedbackIntegration };
export { replayIntegrationShim as replayIntegration };
export { consoleLoggingIntegrationShim as consoleLoggingIntegration, loggerShim as logger };
packages/browser/test/index.bundle.{FEATURE_COMBO}.test.tsimport { logger as coreLogger, metrics as coreMetrics } from '@sentry/core';
import { describe, expect, it } from 'vitest';
// Import real integrations for features included in the bundle
import { browserTracingIntegration, feedbackAsyncIntegration, replayIntegration } from '../src';
import * as Bundle from '../src/index.bundle.{FEATURE_COMBO}';
describe('index.bundle.{FEATURE_COMBO}', () => {
it('has correct exports', () => {
// Test real exports match core implementations
expect(Bundle.browserTracingIntegration).toBe(browserTracingIntegration); // if tracing included
expect(Bundle.feedbackAsyncIntegration).toBe(feedbackAsyncIntegration); // if feedback included
expect(Bundle.replayIntegration).toBe(replayIntegration); // if replay included
expect(Bundle.logger).toBe(coreLogger); // if logs included
expect(Bundle.metrics).toBe(coreMetrics); // always (in base bundle)
});
});
packages/browser/rollup.bundle.config.mjsAdd bundle config before builds.push(...):
const {featureCombo}BaseBundleConfig = makeBaseBundleConfig({
bundleType: 'standalone',
entrypoints: ['src/index.bundle.{FEATURE_COMBO}.ts'],
licenseTitle: '@sentry/browser ({Human Readable Feature List})',
outputFileBase: () => 'bundles/bundle.{FEATURE_COMBO}',
});
Add to builds.push(...):
...makeBundleConfigVariants({featureCombo}BaseBundleConfig),
.size-limit.jsAdd two entries in the "Browser CDN bundles" section:
// Gzipped (add after similar bundles)
{
name: 'CDN Bundle (incl. {Human Readable Features})',
path: createCDNPath('bundle.{FEATURE_COMBO}.min.js'),
gzip: true,
limit: '{SIZE} KB', // Estimate based on features
},
// Uncompressed (add in the non-gzipped section)
{
name: 'CDN Bundle (incl. {Human Readable Features}) - uncompressed',
path: createCDNPath('bundle.{FEATURE_COMBO}.min.js'),
gzip: false,
brotli: false,
limit: '{SIZE} KB', // ~3x the gzipped size
},
Use these approximate sizes when setting limits in .size-limit.js:
| Feature | Gzipped Size |
|---|---|
| Base bundle | ~28 KB |
| + Tracing | +15 KB |
| + Replay | +37 KB |
| + Feedback | +12 KB |
| + Logs | +1 KB |
Uncompressed size is approximately 3x the gzipped size.
dev-packages/browser-integration-tests/package.jsonAdd test scripts in the scripts section:
"test:bundle:{feature_combo}": "PW_BUNDLE=bundle_{feature_combo} yarn test",
"test:bundle:{feature_combo}:min": "PW_BUNDLE=bundle_{feature_combo}_min yarn test",
"test:bundle:{feature_combo}:debug_min": "PW_BUNDLE=bundle_{feature_combo}_debug_min yarn test",
dev-packages/browser-integration-tests/utils/generatePlugin.tsAdd entries to BUNDLE_PATHS.browser:
bundle_{feature_combo}: 'build/bundles/bundle.{FEATURE_COMBO}.js',
bundle_{feature_combo}_min: 'build/bundles/bundle.{FEATURE_COMBO}.min.js',
bundle_{feature_combo}_debug_min: 'build/bundles/bundle.{FEATURE_COMBO}.debug.min.js',
.github/workflows/build.ymlAdd to the bundle matrix (in the job_browser_playwright_tests job):
- bundle_{feature_combo}
After making changes:
yarn lint to check for linting issuescd packages/browser && yarn build:dev to verify TypeScript compilationcd packages/browser && yarn test to run the unit testsLook at these existing bundles for reference:
packages/browser/src/index.bundle.tracing.ts - Tracing onlypackages/browser/src/index.bundle.replay.ts - Replay onlypackages/browser/src/index.bundle.tracing.replay.ts - Tracing + Replaypackages/browser/src/index.bundle.logs.metrics.ts - Logs + Metricsyarn fix to auto-fix common issues