Skip to content
Merged
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
27 changes: 26 additions & 1 deletion packages/cloudflare/src/vite/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,28 @@ function wrapDefaultSpecifier(localName: string, state: TransformState): string
return '__SENTRY_DEFAULT_EXPORT__ as default';
}

/**
* `export { default } from './handler'`. The handler may already be wrapped in its own module,
* which this transform cannot see, so the emitted guard returns such a handler as-is.
*/
function wrapDefaultReexport(
localName: string,
sourceLiteral: string,
state: TransformState,
prelude: string[],
): string {
const target = '__SENTRY_REEXPORT_default__';
prelude.push(
localName === DEFAULT_IMPORT
? `import ${target} from ${sourceLiteral};`
: `import { ${localName} as ${target} } from ${sourceLiteral};`,
`const __SENTRY_DEFAULT_EXPORT__ = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.withSentry, ${state.optionsFn}, ${target});`,
);
Comment thread
cursor[bot] marked this conversation as resolved.
state.needsImport = true;
state.autoWrapped.add(DEFAULT_EXPORT);
return '__SENTRY_DEFAULT_EXPORT__ as default';
}

/**
* Handle one export specifier, returning the `Wrapped as Exported` pair to emit for a class that
* gets wrapped. The import/wrapper statements a cross-module pair depends on are pushed onto
Expand Down Expand Up @@ -593,7 +615,10 @@ function wrapSpecifier(

if (!exportedName || !localName) return undefined;
if (!kind) {
return exportedName === DEFAULT_IMPORT && !sourceLiteral ? wrapDefaultSpecifier(localName, state) : undefined;
if (exportedName !== DEFAULT_IMPORT) return undefined;
return sourceLiteral
? wrapDefaultReexport(localName, sourceLiteral, state, prelude)
: wrapDefaultSpecifier(localName, state);
}

// Without a `from` clause the specifier points at a module-local binding.
Expand Down
50 changes: 50 additions & 0 deletions packages/cloudflare/test/vite/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,46 @@ describe('default export wrapping', () => {
expect(transform(code, ctx)).toBeUndefined();
});

it('wraps a default re-export from another module', () => {
const code = "export { default } from './handler';";

expect(transform(code, ctx)!.code).toBe(
[
"import * as __SENTRY__ from '@sentry/cloudflare';",
"import __SENTRY_REEXPORT_default__ from './handler';",
'const __SENTRY_DEFAULT_EXPORT__ = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.withSentry, (env) => ({}), __SENTRY_REEXPORT_default__);',
'export { __SENTRY_DEFAULT_EXPORT__ as default };',
].join('\n'),
);
});

it('wraps a named export of another module re-exported as default', () => {
const code = "export { handler as default } from './handler';";

expect(transform(code, ctx)!.code).toBe(
[
"import * as __SENTRY__ from '@sentry/cloudflare';",
"import { handler as __SENTRY_REEXPORT_default__ } from './handler';",
'const __SENTRY_DEFAULT_EXPORT__ = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.withSentry, (env) => ({}), __SENTRY_REEXPORT_default__);',
'export { __SENTRY_DEFAULT_EXPORT__ as default };',
].join('\n'),
);
});

it('leaves sibling specifiers of a default re-export untouched', () => {
const code = "export { default, helper } from './handler';";

expect(transform(code, ctx)!.code).toBe(
[
"import * as __SENTRY__ from '@sentry/cloudflare';",
"import __SENTRY_REEXPORT_default__ from './handler';",
'const __SENTRY_DEFAULT_EXPORT__ = __SENTRY__._INTERNAL_wrapUnlessInstrumented(__SENTRY__.withSentry, (env) => ({}), __SENTRY_REEXPORT_default__);',
'export { __SENTRY_DEFAULT_EXPORT__ as default };',
"export { helper } from './handler';",
].join('\n'),
);
});

it('uses custom options callback', () => {
const custom: TransformContext = {
classWrappers: doWrappers(),
Expand Down Expand Up @@ -1118,6 +1158,16 @@ describe('same-worker RPC binding floor', () => {
expect(result.code).toContain('rpcTracePropagationBindings: ["SELF",');
});

it('enables a self service binding when it wrapped a default re-export', () => {
const result = transform("export { default } from './handler';", {
classWrappers: doWrappers(),
optionsFn: '() => undefined',
sameWorkerBindings: [{ bindingName: 'SELF', className: DEFAULT_EXPORT }],
})!;

expect(result.code).toContain('rpcTracePropagationBindings: ["SELF",');
});

it('enables a self service binding when the default export re-exports an already wrapped class', () => {
const code = [
"import { WorkerEntrypoint } from 'cloudflare:workers';",
Expand Down
Loading