Skip to content

Commit 7eb02b3

Browse files
committed
instrument file path configurable
1 parent 379adc7 commit 7eb02b3

File tree

3 files changed

+93
-8
lines changed

3 files changed

+93
-8
lines changed

packages/tanstackstart-react/src/vite/copyInstrumentationFile.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,17 @@ import * as path from 'path';
44
import type { Plugin, ResolvedConfig } from 'vite';
55

66
/**
7-
* Creates a Vite plugin that copies the user's `instrument.server.mjs` file
7+
* Creates a Vite plugin that copies the user's instrumentation file
88
* to the server build output directory after the build completes.
99
*
10+
* By default, copies `instrument.server.mjs` from the project root.
11+
* A custom file path can be provided via `instrumentationFilePath`.
12+
*
1013
* Supports:
1114
* - Nitro deployments (reads output dir from the Nitro Vite environment config)
1215
* - Cloudflare/Netlify deployments (outputs to `dist/server`)
1316
*/
14-
export function makeCopyInstrumentationFilePlugin(): Plugin {
17+
export function makeCopyInstrumentationFilePlugin(instrumentationFilePath?: string): Plugin {
1518
let serverOutputDir: string | undefined;
1619

1720
return {
@@ -57,34 +60,36 @@ export function makeCopyInstrumentationFilePlugin(): Plugin {
5760
return;
5861
}
5962

60-
const instrumentationSource = path.resolve(process.cwd(), 'instrument.server.mjs');
63+
const instrumentationFileName = instrumentationFilePath || 'instrument.server.mjs';
64+
const instrumentationSource = path.resolve(process.cwd(), instrumentationFileName);
6165

6266
try {
6367
await fs.promises.access(instrumentationSource, fs.constants.F_OK);
6468
} catch {
6569
consoleSandbox(() => {
6670
// eslint-disable-next-line no-console
6771
console.warn(
68-
'[Sentry TanStack Start] No instrument.server.mjs file found in project root. ' +
72+
`[Sentry TanStack Start] No ${instrumentationFileName} file found in project root. ` +
6973
'The Sentry instrumentation file will not be copied to the build output.',
7074
);
7175
});
7276
return;
7377
}
7478

75-
const destination = path.resolve(serverOutputDir, 'instrument.server.mjs');
79+
const destinationFileName = path.basename(instrumentationFileName);
80+
const destination = path.resolve(serverOutputDir, destinationFileName);
7681

7782
try {
7883
await fs.promises.mkdir(serverOutputDir, { recursive: true });
7984
await fs.promises.copyFile(instrumentationSource, destination);
8085
consoleSandbox(() => {
8186
// eslint-disable-next-line no-console
82-
console.log(`[Sentry TanStack Start] Copied instrument.server.mjs to ${destination}`);
87+
console.log(`[Sentry TanStack Start] Copied ${destinationFileName} to ${destination}`);
8388
});
8489
} catch (error) {
8590
consoleSandbox(() => {
8691
// eslint-disable-next-line no-console
87-
console.warn('[Sentry TanStack Start] Failed to copy instrument.server.mjs to build output.', error);
92+
console.warn(`[Sentry TanStack Start] Failed to copy ${destinationFileName} to build output.`, error);
8893
});
8994
}
9095
},

packages/tanstackstart-react/src/vite/sentryTanstackStart.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ export interface SentryTanstackStartOptions extends BuildTimeOptionsBase {
2020
* @default true
2121
*/
2222
autoInstrumentMiddleware?: boolean;
23+
24+
/**
25+
* Path to the instrumentation file to be copied to the server build output directory.
26+
*
27+
* Relative paths are resolved from the current working directory.
28+
*
29+
* @default 'instrument.server.mjs'
30+
*/
31+
instrumentationFilePath?: string;
2332
}
2433

2534
/**
@@ -55,7 +64,7 @@ export function sentryTanstackStart(options: SentryTanstackStartOptions = {}): P
5564
const plugins: Plugin[] = [...makeAddSentryVitePlugin(options)];
5665

5766
// copy instrumentation file to build output
58-
plugins.push(makeCopyInstrumentationFilePlugin());
67+
plugins.push(makeCopyInstrumentationFilePlugin(options.instrumentationFilePath));
5968

6069
// middleware auto-instrumentation
6170
if (options.autoInstrumentMiddleware !== false) {

packages/tanstackstart-react/test/vite/copyInstrumentationFile.test.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,77 @@ describe('makeCopyInstrumentationFilePlugin()', () => {
262262
'[Sentry TanStack Start] Failed to copy instrument.server.mjs to build output.',
263263
expect.any(Error),
264264
);
265+
});
266+
267+
it('uses custom instrumentation file path when provided', async () => {
268+
const customPlugin = makeCopyInstrumentationFilePlugin('custom/path/my-instrument.mjs');
269+
270+
const resolvedConfig = {
271+
root: '/project',
272+
plugins: [{ name: 'nitro' }],
273+
environments: {
274+
nitro: {
275+
build: {
276+
rollupOptions: {
277+
output: {
278+
dir: '/project/.output/server',
279+
},
280+
},
281+
},
282+
},
283+
},
284+
} as unknown as ResolvedConfig;
285+
286+
(customPlugin.configResolved as AnyFunction)(resolvedConfig);
287+
288+
vi.mocked(fs.promises.access).mockResolvedValueOnce(undefined);
289+
vi.mocked(fs.promises.mkdir).mockResolvedValueOnce(undefined);
290+
vi.mocked(fs.promises.copyFile).mockResolvedValueOnce(undefined);
291+
292+
await (customPlugin.closeBundle as AnyFunction)();
293+
294+
expect(fs.promises.access).toHaveBeenCalledWith(
295+
path.resolve(process.cwd(), 'custom/path/my-instrument.mjs'),
296+
fs.constants.F_OK,
297+
);
298+
expect(fs.promises.copyFile).toHaveBeenCalledWith(
299+
path.resolve(process.cwd(), 'custom/path/my-instrument.mjs'),
300+
path.resolve('/project/.output/server', 'my-instrument.mjs'),
301+
);
302+
});
303+
304+
it('warns with custom file name when custom instrumentation file is not found', async () => {
305+
const customPlugin = makeCopyInstrumentationFilePlugin('custom/my-instrument.mjs');
306+
307+
const resolvedConfig = {
308+
root: '/project',
309+
plugins: [{ name: 'nitro' }],
310+
environments: {
311+
nitro: {
312+
build: {
313+
rollupOptions: {
314+
output: {
315+
dir: '/project/.output/server',
316+
},
317+
},
318+
},
319+
},
320+
},
321+
} as unknown as ResolvedConfig;
322+
323+
(customPlugin.configResolved as AnyFunction)(resolvedConfig);
324+
325+
vi.mocked(fs.promises.access).mockRejectedValueOnce(new Error('ENOENT'));
326+
327+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
328+
329+
await (customPlugin.closeBundle as AnyFunction)();
330+
331+
expect(warnSpy).toHaveBeenCalledWith(
332+
'[Sentry TanStack Start] No custom/my-instrument.mjs file found in project root. ' +
333+
'The Sentry instrumentation file will not be copied to the build output.',
334+
);
335+
expect(fs.promises.copyFile).not.toHaveBeenCalled();
265336

266337
warnSpy.mockRestore();
267338
});

0 commit comments

Comments
 (0)