Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,8 @@
"[typescript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
},
"oxc.suppressProgramErrors": true
"oxc.suppressProgramErrors": true,
"[javascript]": {
"editor.defaultFormatter": "oxc.oxc-vscode"
}
}
79 changes: 46 additions & 33 deletions dev-packages/rollup-utils/bundleHelpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -135,55 +135,68 @@ export function makeBaseBundleConfig(options) {
});
}

/**
* @param {import('rollup').RollupOptions} baseConfig
* @param {string} variant
*/
function getVariantSpecificBundleConfig(baseConfig, variant) {
const baseEntryNames = baseConfig.output.entryFileNames;

switch (variant) {
case '.js':
return {
output: {
entryFileNames: chunkInfo => `${baseEntryNames(chunkInfo)}.js`,
},
plugins: [makeIsDebugBuildPlugin(true), makeSetSDKSourcePlugin('cdn')],
};
case '.min.js':
return {
output: {
entryFileNames: chunkInfo => `${baseEntryNames(chunkInfo)}.min.js`,
},
plugins: [makeIsDebugBuildPlugin(false), makeSetSDKSourcePlugin('cdn'), makeTerserPlugin()],
};
case '.debug.min.js':
return {
output: {
entryFileNames: chunkInfo => `${baseEntryNames(chunkInfo)}.debug.min.js`,
},
plugins: [makeIsDebugBuildPlugin(true), makeSetSDKSourcePlugin('cdn'), makeTerserPlugin()],
};
default:
throw new Error(`Unknown bundle variant requested: ${variant}`);
}
}

/**
* Takes the CDN rollup config for a given package and produces three versions of it:
* - non-minified, including debug logging,
* - minified, including debug logging,
* - minified, with debug logging stripped
*
* @param baseConfig The rollup config shared by the entire package
* @returns An array of versions of that config
* Pass `() => makeBaseBundleConfig({ ... })` so each variant gets a fresh base config (new plugin instances). That
* avoids sharing stateful Rollup plugins when `rollupParallel` runs multiple `rollup()` calls concurrently. Passing a
* plain config object is supported for backwards compatibility but only shallow-clones plugin shells.
*
* @param {(() => import('rollup').RollupOptions) | import('rollup').RollupOptions} getBaseConfigOrConfig
* @param {{ variants?: string[] }} [options]
*/
export function makeBundleConfigVariants(baseConfig, options = {}) {
export function makeBundleConfigVariants(getBaseConfigOrConfig, options = {}) {
const { variants = BUNDLE_VARIANTS } = options;

const includeDebuggingPlugin = makeIsDebugBuildPlugin(true);
const stripDebuggingPlugin = makeIsDebugBuildPlugin(false);
const terserPlugin = makeTerserPlugin();
const setSdkSourcePlugin = makeSetSDKSourcePlugin('cdn');

// The additional options to use for each variant we're going to create.
const variantSpecificConfigMap = {
'.js': {
output: {
entryFileNames: chunkInfo => `${baseConfig.output.entryFileNames(chunkInfo)}.js`,
},
plugins: [includeDebuggingPlugin, setSdkSourcePlugin],
},

'.min.js': {
output: {
entryFileNames: chunkInfo => `${baseConfig.output.entryFileNames(chunkInfo)}.min.js`,
},
plugins: [stripDebuggingPlugin, setSdkSourcePlugin, terserPlugin],
},

'.debug.min.js': {
output: {
entryFileNames: chunkInfo => `${baseConfig.output.entryFileNames(chunkInfo)}.debug.min.js`,
},
plugins: [includeDebuggingPlugin, setSdkSourcePlugin, terserPlugin],
},
};
const resolveBase = typeof getBaseConfigOrConfig === 'function' ? getBaseConfigOrConfig : () => getBaseConfigOrConfig;

return variants.map(variant => {
if (!BUNDLE_VARIANTS.includes(variant)) {
throw new Error(`Unknown bundle variant requested: ${variant}`);
}
return deepMerge(baseConfig, variantSpecificConfigMap[variant], {
const baseConfig = resolveBase();
const merged = deepMerge(baseConfig, getVariantSpecificBundleConfig(baseConfig, variant), {
// Merge the plugin arrays and make sure the end result is in the correct order. Everything else can use the
// default merge strategy.
customMerge: key => (key === 'plugins' ? mergePlugins : undefined),
});

return merged;
});
}
36 changes: 36 additions & 0 deletions dev-packages/rollup-utils/rollupParallel.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable no-console */

/**
* Runs rollup builds in parallel for configs that export an array.
* Usage: node rollupParallel.mjs <config-path>
*/
import { availableParallelism } from 'os';
import { pathToFileURL } from 'url';
import { resolve } from 'path';
import { rollup } from 'rollup';

const configPath = process.argv[2];
if (!configPath) {
console.error('Usage: node rollupParallel.mjs <config-path>');
process.exit(1);
}

const { default: configs } = await import(pathToFileURL(resolve(configPath)).href);
const concurrency = availableParallelism();
const queue = [...configs];
let done = 0;

async function worker() {
while (queue.length > 0) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

l: We could abort once a worker failed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

hmm not sure what would be more helpful here actually 🤔 but I suppose if rollup() fails this would throw an error and abort the while thing anyhow..?

const config = queue.shift();
const bundle = await rollup({ ...config, onwarn: console.warn });
await bundle.write(config.output);
Comment thread
cursor[bot] marked this conversation as resolved.
await bundle.close();
done++;
process.stdout.write(`\r [${done}/${configs.length}] builds completed`);
}
Comment thread
cursor[bot] marked this conversation as resolved.
}

console.log(`Running ${configs.length} rollup builds (concurrency: ${concurrency})...`);
await Promise.all(Array.from({ length: concurrency }, worker));
console.log('\nDone.');
6 changes: 3 additions & 3 deletions docs/adding-cdn-bundle.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,18 +130,18 @@ describe('index.bundle.{FEATURE_COMBO}', () => {
Add bundle config before `builds.push(...)`:

```javascript
const {featureCombo}BaseBundleConfig = makeBaseBundleConfig({
const {featureCombo}BaseBundleOptions = {
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(...)`:

```javascript
...makeBundleConfigVariants({featureCombo}BaseBundleConfig),
...makeBundleConfigVariants(() => makeBaseBundleConfig({featureCombo}BaseBundleOptions)),
```

### 4. `.size-limit.js`
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
"scripts": {
"build": "run-p build:transpile build:bundle build:types",
"build:dev": "run-p build:transpile build:types",
"build:bundle": "rollup -c rollup.bundle.config.mjs",
"build:bundle": "node ../../dev-packages/rollup-utils/rollupParallel.mjs rollup.bundle.config.mjs",
"build:transpile": "rollup -c rollup.npm.config.mjs",
"build:types": "run-s build:types:core build:types:downlevel",
"build:types:core": "tsc -p tsconfig.types.json",
Expand Down
110 changes: 57 additions & 53 deletions packages/browser/rollup.bundle.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,35 @@ const reexportedPluggableIntegrationFiles = [
];

browserPluggableIntegrationFiles.forEach(integrationName => {
const integrationsBundleConfig = makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: [`src/integrations/${integrationName}.ts`],
licenseTitle: `@sentry/browser - ${integrationName}`,
outputFileBase: () => `bundles/${integrationName}`,
});

builds.push(...makeBundleConfigVariants(integrationsBundleConfig));
builds.push(
...makeBundleConfigVariants(() =>
makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: [`src/integrations/${integrationName}.ts`],
licenseTitle: `@sentry/browser - ${integrationName}`,
outputFileBase: () => `bundles/${integrationName}`,
}),
),
);
});

reexportedPluggableIntegrationFiles.forEach(integrationName => {
const integrationsBundleConfig = makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: [`src/integrations-bundle/index.${integrationName}.ts`],
licenseTitle: `@sentry/browser - ${integrationName}`,
outputFileBase: () => `bundles/${integrationName}`,
});

builds.push(...makeBundleConfigVariants(integrationsBundleConfig));
builds.push(
...makeBundleConfigVariants(() =>
makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: [`src/integrations-bundle/index.${integrationName}.ts`],
licenseTitle: `@sentry/browser - ${integrationName}`,
outputFileBase: () => `bundles/${integrationName}`,
}),
),
);
});

// Bundle config for additional exports we don't want to include in the main SDK bundle
// if we need more of these, we can generalize the config as for pluggable integrations
builds.push(
...makeBundleConfigVariants(
...makeBundleConfigVariants(() =>
makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: ['src/pluggable-exports-bundle/index.multiplexedtransport.ts'],
Expand All @@ -56,104 +60,104 @@ builds.push(
),
);

const baseBundleConfig = makeBaseBundleConfig({
const baseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.ts'],
licenseTitle: '@sentry/browser',
outputFileBase: () => 'bundles/bundle',
});
};

const feedbackBaseBundleConfig = makeBaseBundleConfig({
const feedbackBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.feedback.ts'],
licenseTitle: '@sentry/browser & @sentry/feedback',
outputFileBase: () => 'bundles/bundle.feedback',
});
};

const logsMetricsBaseBundleConfig = makeBaseBundleConfig({
const logsMetricsBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.logs.metrics.ts'],
licenseTitle: '@sentry/browser (Logs and Metrics)',
outputFileBase: () => 'bundles/bundle.logs.metrics',
});
};

const replayBaseBundleConfig = makeBaseBundleConfig({
const replayBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.replay.ts'],
licenseTitle: '@sentry/browser (Replay)',
outputFileBase: () => 'bundles/bundle.replay',
});
};

const replayFeedbackBaseBundleConfig = makeBaseBundleConfig({
const replayFeedbackBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.replay.feedback.ts'],
licenseTitle: '@sentry/browser (Replay, and Feedback)',
outputFileBase: () => 'bundles/bundle.replay.feedback',
});
};

const replayLogsMetricsBaseBundleConfig = makeBaseBundleConfig({
const replayLogsMetricsBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.replay.logs.metrics.ts'],
licenseTitle: '@sentry/browser (Replay, Logs, and Metrics)',
outputFileBase: () => 'bundles/bundle.replay.logs.metrics',
});
};

// Tracing
const tracingBaseBundleConfig = makeBaseBundleConfig({
const tracingBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring)',
outputFileBase: () => 'bundles/bundle.tracing',
});
};

const tracingLogsMetricsBaseBundleConfig = makeBaseBundleConfig({
const tracingLogsMetricsBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.logs.metrics.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring, Logs, and Metrics)',
outputFileBase: () => 'bundles/bundle.tracing.logs.metrics',
});
};

const tracingReplayBaseBundleConfig = makeBaseBundleConfig({
const tracingReplayBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.replay.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring and Replay)',
outputFileBase: () => 'bundles/bundle.tracing.replay',
});
};

const tracingReplayLogsMetricsBaseBundleConfig = makeBaseBundleConfig({
const tracingReplayLogsMetricsBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.replay.logs.metrics.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring, Replay, Logs, and Metrics)',
outputFileBase: () => 'bundles/bundle.tracing.replay.logs.metrics',
});
};

const tracingReplayFeedbackBaseBundleConfig = makeBaseBundleConfig({
const tracingReplayFeedbackBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.replay.feedback.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring, Replay, and Feedback)',
outputFileBase: () => 'bundles/bundle.tracing.replay.feedback',
});
};

const tracingReplayFeedbackLogsMetricsBaseBundleConfig = makeBaseBundleConfig({
const tracingReplayFeedbackLogsMetricsBaseBundleOptions = {
bundleType: 'standalone',
entrypoints: ['src/index.bundle.tracing.replay.feedback.logs.metrics.ts'],
licenseTitle: '@sentry/browser (Performance Monitoring, Replay, Feedback, Logs, and Metrics)',
outputFileBase: () => 'bundles/bundle.tracing.replay.feedback.logs.metrics',
});
};

builds.push(
...makeBundleConfigVariants(baseBundleConfig),
...makeBundleConfigVariants(feedbackBaseBundleConfig),
...makeBundleConfigVariants(logsMetricsBaseBundleConfig),
...makeBundleConfigVariants(replayBaseBundleConfig),
...makeBundleConfigVariants(replayFeedbackBaseBundleConfig),
...makeBundleConfigVariants(replayLogsMetricsBaseBundleConfig),
...makeBundleConfigVariants(tracingBaseBundleConfig),
...makeBundleConfigVariants(tracingLogsMetricsBaseBundleConfig),
...makeBundleConfigVariants(tracingReplayBaseBundleConfig),
...makeBundleConfigVariants(tracingReplayLogsMetricsBaseBundleConfig),
...makeBundleConfigVariants(tracingReplayFeedbackBaseBundleConfig),
...makeBundleConfigVariants(tracingReplayFeedbackLogsMetricsBaseBundleConfig),
...makeBundleConfigVariants(() => makeBaseBundleConfig(baseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(feedbackBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(logsMetricsBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(replayBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(replayFeedbackBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(replayLogsMetricsBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingLogsMetricsBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingReplayBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingReplayLogsMetricsBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingReplayFeedbackBaseBundleOptions)),
...makeBundleConfigVariants(() => makeBaseBundleConfig(tracingReplayFeedbackLogsMetricsBaseBundleOptions)),
);

export default builds;
4 changes: 2 additions & 2 deletions packages/feedback/rollup.bundle.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal
export default [
// The core `feedback` bundle is built in the browser package
// Sub-bundles are built here
...makeBundleConfigVariants(
...makeBundleConfigVariants(() =>
makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: ['src/screenshot/integration.ts'],
Expand All @@ -19,7 +19,7 @@ export default [
},
}),
),
...makeBundleConfigVariants(
...makeBundleConfigVariants(() =>
makeBaseBundleConfig({
bundleType: 'addon',
entrypoints: ['src/modal/integration.tsx'],
Expand Down
Loading
Loading