Skip to content

feat(react-router): Create a Vite plugin that injects sentryConfig into the global vite config #16197

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 6, 2025
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
1 change: 1 addition & 0 deletions packages/react-router/src/vite/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { sentryReactRouter } from './plugin';
export { sentryOnBuildEnd } from './buildEnd/handleOnBuildEnd';
export type { SentryReactRouterBuildOptions } from './types';
export { makeConfigInjectorPlugin } from './makeConfigInjectorPlugin';
23 changes: 23 additions & 0 deletions packages/react-router/src/vite/makeConfigInjectorPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { type Plugin } from 'vite';
import type { SentryReactRouterBuildOptions } from './types';

/**
* Creates a Vite plugin that injects the Sentry options into the global Vite config.
* This ensures the sentryConfig is available to other components that need access to it,
* like the buildEnd hook.
*
* @param options - Configuration options for the Sentry Vite plugin
* @returns A Vite plugin that injects sentryConfig into the global config
*/
export function makeConfigInjectorPlugin(options: SentryReactRouterBuildOptions): Plugin {
return {
name: 'sentry-react-router-config-injector',
enforce: 'pre',
config(config) {
return {
...config,
sentryConfig: options,
};
},
};
}
3 changes: 3 additions & 0 deletions packages/react-router/src/vite/plugin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { ConfigEnv } from 'vite';
import { type Plugin } from 'vite';
import { makeConfigInjectorPlugin } from './makeConfigInjectorPlugin';
import { makeCustomSentryVitePlugins } from './makeCustomSentryVitePlugins';
import { makeEnableSourceMapsPlugin } from './makeEnableSourceMapsPlugin';
import type { SentryReactRouterBuildOptions } from './types';
Expand All @@ -17,6 +18,8 @@ export async function sentryReactRouter(
): Promise<Plugin[]> {
const plugins: Plugin[] = [];

plugins.push(makeConfigInjectorPlugin(options));

if (process.env.NODE_ENV !== 'development' && config.command === 'build' && config.mode !== 'development') {
plugins.push(makeEnableSourceMapsPlugin(options));
plugins.push(...(await makeCustomSentryVitePlugins(options)));
Expand Down
22 changes: 14 additions & 8 deletions packages/react-router/test/vite/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { makeConfigInjectorPlugin } from '../../src/vite/makeConfigInjectorPlugin';
import { makeCustomSentryVitePlugins } from '../../src/vite/makeCustomSentryVitePlugins';
import { makeEnableSourceMapsPlugin } from '../../src/vite/makeEnableSourceMapsPlugin';
import { sentryReactRouter } from '../../src/vite/plugin';
Expand All @@ -12,57 +13,61 @@ vi.spyOn(console, 'warn').mockImplementation(() => {

vi.mock('../../src/vite/makeCustomSentryVitePlugins');
vi.mock('../../src/vite/makeEnableSourceMapsPlugin');
vi.mock('../../src/vite/makeConfigInjectorPlugin');

describe('sentryReactRouter', () => {
const mockPlugins = [{ name: 'test-plugin' }];
const mockSourceMapsPlugin = { name: 'source-maps-plugin' };
const mockConfigInjectorPlugin = { name: 'sentry-config-injector' };

beforeEach(() => {
vi.clearAllMocks();
vi.mocked(makeCustomSentryVitePlugins).mockResolvedValue(mockPlugins);
vi.mocked(makeEnableSourceMapsPlugin).mockReturnValue(mockSourceMapsPlugin);
vi.mocked(makeConfigInjectorPlugin).mockReturnValue(mockConfigInjectorPlugin);
});

afterEach(() => {
vi.resetModules();
});

it('should return an empty array in development mode', async () => {
it('should return sentry config injector plugin in development mode', async () => {
const originalNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'development';

const result = await sentryReactRouter({}, { command: 'build', mode: 'production' });

expect(result).toEqual([]);
expect(result).toEqual([mockConfigInjectorPlugin]);
expect(makeCustomSentryVitePlugins).not.toHaveBeenCalled();
expect(makeEnableSourceMapsPlugin).not.toHaveBeenCalled();

process.env.NODE_ENV = originalNodeEnv;
});

it('should return an empty array when not in build mode', async () => {
it('should return config injector plugin when not in build mode', async () => {
const result = await sentryReactRouter({}, { command: 'serve', mode: 'production' });

expect(result).toEqual([]);
expect(result).toEqual([mockConfigInjectorPlugin]);
expect(makeCustomSentryVitePlugins).not.toHaveBeenCalled();
expect(makeEnableSourceMapsPlugin).not.toHaveBeenCalled();
});

it('should return an empty array when in development mode', async () => {
it('should return config injector plugin in development build mode', async () => {
const result = await sentryReactRouter({}, { command: 'build', mode: 'development' });

expect(result).toEqual([]);
expect(result).toEqual([mockConfigInjectorPlugin]);
expect(makeCustomSentryVitePlugins).not.toHaveBeenCalled();
expect(makeEnableSourceMapsPlugin).not.toHaveBeenCalled();
});

it('should return plugins in production build mode', async () => {
it('should return all plugins in production build mode', async () => {
const originalNodeEnv = process.env.NODE_ENV;
process.env.NODE_ENV = 'production';

const result = await sentryReactRouter({}, { command: 'build', mode: 'production' });

expect(result).toEqual([mockSourceMapsPlugin, ...mockPlugins]);
expect(result).toEqual([mockConfigInjectorPlugin, mockSourceMapsPlugin, ...mockPlugins]);
expect(makeConfigInjectorPlugin).toHaveBeenCalledWith({});
expect(makeCustomSentryVitePlugins).toHaveBeenCalledWith({});
expect(makeEnableSourceMapsPlugin).toHaveBeenCalledWith({});

Expand All @@ -81,6 +86,7 @@ describe('sentryReactRouter', () => {

await sentryReactRouter(options, { command: 'build', mode: 'production' });

expect(makeConfigInjectorPlugin).toHaveBeenCalledWith(options);
expect(makeCustomSentryVitePlugins).toHaveBeenCalledWith(options);
expect(makeEnableSourceMapsPlugin).toHaveBeenCalledWith(options);

Expand Down
Loading