Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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"
}
}
80 changes: 47 additions & 33 deletions dev-packages/rollup-utils/bundleHelpers.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -135,55 +135,69 @@ 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,
};
Comment thread
mydea marked this conversation as resolved.
Outdated
});
}
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