Skip to content

Commit c61d8cd

Browse files
committed
fix(solidstart): Use nitro module for build hooks to preserve preset hooks
Previously, to move the instrumentation file to the build output we added a `rollup:before` hook via nitro's `server.hooks`. This however overrides any nitro preset-defined hooks. Any preset that defines such a hook, has their hook not run. Notably, the `aws-preset` sets up `rollup:before` to switch the entry files when using aws streaming. The fix is to move our hook logic into our own nitro module, which then runs additvely on top of all the other hooks that have been defined by other presets. Closes: #20857
1 parent 22bfd80 commit c61d8cd

2 files changed

Lines changed: 76 additions & 35 deletions

File tree

packages/solidstart/src/config/withSentry.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -36,42 +36,44 @@ export function withSentry(
3636
};
3737

3838
const server = (solidStartConfig.server || {}) as SolidStartInlineServerConfig;
39-
const hooks = server.hooks || {};
4039
const viteConfig = solidStartConfig.vite;
4140
const vite =
4241
typeof viteConfig === 'function'
4342
? (...args: Parameters<typeof viteConfig>) => addSentryPluginToVite(viteConfig(...args), sentryPluginOptions)
4443
: addSentryPluginToVite(viteConfig, sentryPluginOptions);
4544

45+
// Use a module so we don't override preset hooks.
46+
const sentryNitroModule = (nitro: Nitro) => {
47+
nitro.hooks.hook('rollup:before', async (nitro, rollupConfig) => {
48+
if (sentrySolidStartPluginOptions?.autoInjectServerSentry === 'experimental_dynamic-import') {
49+
await addDynamicImportEntryFileWrapper({
50+
nitro,
51+
rollupConfig: rollupConfig as unknown as RollupConfig,
52+
sentryPluginOptions,
53+
});
54+
55+
sentrySolidStartPluginOptions.debug &&
56+
debug.log(
57+
'Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.',
58+
);
59+
} else {
60+
await addInstrumentationFileToBuild(nitro);
61+
62+
if (sentrySolidStartPluginOptions?.autoInjectServerSentry === 'top-level-import') {
63+
await addSentryTopImport(nitro);
64+
}
65+
}
66+
});
67+
};
68+
69+
const existingModules = (server as SolidStartInlineServerConfig & { modules?: unknown[] }).modules || [];
70+
4671
return {
4772
...solidStartConfig,
4873
vite,
4974
server: {
5075
...server,
51-
hooks: {
52-
...hooks,
53-
async 'rollup:before'(nitro: Nitro, config: RollupConfig) {
54-
if (sentrySolidStartPluginOptions?.autoInjectServerSentry === 'experimental_dynamic-import') {
55-
await addDynamicImportEntryFileWrapper({ nitro, rollupConfig: config, sentryPluginOptions });
56-
57-
sentrySolidStartPluginOptions.debug &&
58-
debug.log(
59-
'Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.',
60-
);
61-
} else {
62-
await addInstrumentationFileToBuild(nitro);
63-
64-
if (sentrySolidStartPluginOptions?.autoInjectServerSentry === 'top-level-import') {
65-
await addSentryTopImport(nitro);
66-
}
67-
}
68-
69-
// Run user provided hook
70-
if (hooks['rollup:before']) {
71-
hooks['rollup:before'](nitro);
72-
}
73-
},
74-
},
76+
modules: [...existingModules, sentryNitroModule],
7577
},
7678
};
7779
}

packages/solidstart/test/config/withSentry.test.ts

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,41 @@ describe('withSentry()', () => {
3636
preset: 'vercel',
3737
},
3838
};
39+
const rollupConfig = { plugins: [] };
3940

40-
it('adds a nitro hook to add the instrumentation file to the build if no plugin options are provided', async () => {
41+
function callSentryNitroModule(config: ReturnType<typeof withSentry>): { hookFn: (...args: unknown[]) => unknown } {
42+
const modules = (config?.server as { modules?: unknown[] })?.modules || [];
43+
const sentryModule = modules[modules.length - 1] as (nitro: Nitro) => void;
44+
let hookFn: (...args: unknown[]) => unknown = () => {};
45+
const fakeNitro = {
46+
...nitroOptions,
47+
hooks: {
48+
hook: (_name: string, fn: (...args: unknown[]) => unknown) => {
49+
hookFn = fn;
50+
},
51+
},
52+
} as unknown as Nitro;
53+
sentryModule(fakeNitro);
54+
return { hookFn };
55+
}
56+
57+
it('registers a nitro module that hooks into rollup:before to add the instrumentation file', async () => {
4158
const config = withSentry(solidStartConfig, {});
42-
await config?.server.hooks['rollup:before'](nitroOptions);
59+
const { hookFn } = callSentryNitroModule(config);
60+
await hookFn(nitroOptions, rollupConfig);
4361
expect(addInstrumentationFileToBuildMock).toHaveBeenCalledWith(nitroOptions);
44-
expect(userDefinedNitroRollupBeforeHookMock).toHaveBeenCalledWith(nitroOptions);
4562
});
4663

47-
it('adds a nitro hook to add the instrumentation file as top level import to the server entry file when configured in autoInjectServerSentry', async () => {
64+
it('does not override user-defined hooks in server.hooks', () => {
65+
const config = withSentry(solidStartConfig, {});
66+
expect(config?.server.hooks?.['rollup:before']).toBe(userDefinedNitroRollupBeforeHookMock);
67+
expect(config?.server.hooks?.close).toBe(userDefinedNitroCloseHookMock);
68+
});
69+
70+
it('adds the instrumentation file as top level import when configured as top-level-import', async () => {
4871
const config = withSentry(solidStartConfig, { autoInjectServerSentry: 'top-level-import' });
49-
await config?.server.hooks['rollup:before'](nitroOptions);
50-
await config?.server.hooks['close'](nitroOptions);
72+
const { hookFn } = callSentryNitroModule(config);
73+
await hookFn(nitroOptions, rollupConfig);
5174
expect(addSentryTopImportMock).toHaveBeenCalledWith(
5275
expect.objectContaining({
5376
options: {
@@ -59,15 +82,13 @@ describe('withSentry()', () => {
5982
},
6083
}),
6184
);
62-
expect(userDefinedNitroCloseHookMock).toHaveBeenCalled();
6385
});
6486

6587
it('does not add the instrumentation file as top level import if autoInjectServerSentry is undefined', async () => {
6688
const config = withSentry(solidStartConfig, { autoInjectServerSentry: undefined });
67-
await config?.server.hooks['rollup:before'](nitroOptions);
68-
await config?.server.hooks['close'](nitroOptions);
89+
const { hookFn } = callSentryNitroModule(config);
90+
await hookFn(nitroOptions, rollupConfig);
6991
expect(addSentryTopImportMock).not.toHaveBeenCalled();
70-
expect(userDefinedNitroCloseHookMock).toHaveBeenCalled();
7192
});
7293

7394
it('adds the sentry solidstart vite plugin', () => {
@@ -134,4 +155,22 @@ describe('withSentry()', () => {
134155
'my-test-plugin',
135156
]);
136157
});
158+
159+
it('preserves existing server modules', () => {
160+
const existingModule = vi.fn();
161+
const config = withSentry(
162+
{
163+
...solidStartConfig,
164+
server: {
165+
...solidStartConfig.server,
166+
modules: [existingModule],
167+
},
168+
},
169+
{},
170+
);
171+
const modules = (config?.server as { modules?: unknown[] })?.modules || [];
172+
expect(modules).toHaveLength(2);
173+
expect(modules[0]).toBe(existingModule);
174+
expect(typeof modules[1]).toBe('function');
175+
});
137176
});

0 commit comments

Comments
 (0)