Skip to content

Commit 90f6619

Browse files
XenossolitariusIvan Pesic
and
Ivan Pesic
authored
feat(nuxt): Added support for nuxt layers (#16372)
Added ability to detect and import config files from the **active** nuxt layer with strategy of the **most latest** layer taking precedence. Included fallback behavior for good measure. Rest of the config should be merged as it already is by c12 and defu. Don't think this PR covers the git:repo based layers but those are generally not full supported as well in Nuxt 3 ecosystem. Added basic tests Resolves [#14345](#14345) --------- Co-authored-by: Ivan Pesic <[email protected]>
1 parent bdbd541 commit 90f6619

File tree

3 files changed

+100
-10
lines changed

3 files changed

+100
-10
lines changed

packages/nuxt/src/module.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export default defineNuxtModule<ModuleOptions>({
3535
const moduleDirResolver = createResolver(import.meta.url);
3636
const buildDirResolver = createResolver(nuxt.options.buildDir);
3737

38-
const clientConfigFile = findDefaultSdkInitFile('client');
38+
const clientConfigFile = findDefaultSdkInitFile('client', nuxt);
3939

4040
if (clientConfigFile) {
4141
// Inject the client-side Sentry config file with a side effect import
@@ -59,7 +59,7 @@ export default defineNuxtModule<ModuleOptions>({
5959
addPlugin({ src: moduleDirResolver.resolve('./runtime/plugins/sentry.client'), mode: 'client' });
6060
}
6161

62-
const serverConfigFile = findDefaultSdkInitFile('server');
62+
const serverConfigFile = findDefaultSdkInitFile('server', nuxt);
6363

6464
if (serverConfigFile) {
6565
addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/sentry.server'));

packages/nuxt/src/vite/utils.ts

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,49 @@
11
import { consoleSandbox } from '@sentry/core';
22
import * as fs from 'fs';
3+
import type { Nuxt } from 'nuxt/schema';
34
import * as path from 'path';
45

56
/**
67
* Find the default SDK init file for the given type (client or server).
78
* The sentry.server.config file is prioritized over the instrument.server file.
89
*/
9-
export function findDefaultSdkInitFile(type: 'server' | 'client'): string | undefined {
10+
export function findDefaultSdkInitFile(type: 'server' | 'client', nuxt?: Nuxt): string | undefined {
1011
const possibleFileExtensions = ['ts', 'js', 'mjs', 'cjs', 'mts', 'cts'];
11-
const cwd = process.cwd();
12+
const relativePaths: string[] = [];
1213

13-
const filePaths: string[] = [];
1414
if (type === 'server') {
1515
for (const ext of possibleFileExtensions) {
16-
// order is important here - we want to prioritize the server.config file
17-
filePaths.push(path.join(cwd, `sentry.${type}.config.${ext}`));
18-
filePaths.push(path.join(cwd, 'public', `instrument.${type}.${ext}`));
16+
relativePaths.push(`sentry.${type}.config.${ext}`);
17+
relativePaths.push(path.join('public', `instrument.${type}.${ext}`));
1918
}
2019
} else {
2120
for (const ext of possibleFileExtensions) {
22-
filePaths.push(path.join(cwd, `sentry.${type}.config.${ext}`));
21+
relativePaths.push(`sentry.${type}.config.${ext}`);
22+
}
23+
}
24+
25+
// Get layers from highest priority to lowest
26+
const layers = [...(nuxt?.options._layers ?? [])].reverse();
27+
28+
for (const layer of layers) {
29+
for (const relativePath of relativePaths) {
30+
const fullPath = path.resolve(layer.cwd, relativePath);
31+
if (fs.existsSync(fullPath)) {
32+
return fullPath;
33+
}
34+
}
35+
}
36+
37+
// As a fallback, also check CWD (left for pure compatibility)
38+
const cwd = process.cwd();
39+
for (const relativePath of relativePaths) {
40+
const fullPath = path.resolve(cwd, relativePath);
41+
if (fs.existsSync(fullPath)) {
42+
return fullPath;
2343
}
2444
}
2545

26-
return filePaths.find(filename => fs.existsSync(filename));
46+
return undefined;
2747
}
2848

2949
/**

packages/nuxt/test/vite/utils.test.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as fs from 'fs';
2+
import type { Nuxt } from 'nuxt/schema';
23
import { afterEach, describe, expect, it, vi } from 'vitest';
34
import {
45
constructFunctionReExport,
@@ -69,6 +70,75 @@ describe('findDefaultSdkInitFile', () => {
6970
const result = findDefaultSdkInitFile('server');
7071
expect(result).toMatch('packages/nuxt/sentry.server.config.js');
7172
});
73+
74+
it('should return the latest layer config file path if client config exists', () => {
75+
vi.spyOn(fs, 'existsSync').mockImplementation(filePath => {
76+
return !(filePath instanceof URL) && filePath.includes('sentry.client.config.ts');
77+
});
78+
79+
const nuxtMock = {
80+
options: {
81+
_layers: [
82+
{
83+
cwd: 'packages/nuxt/module',
84+
},
85+
{
86+
cwd: 'packages/nuxt',
87+
},
88+
],
89+
},
90+
} as Nuxt;
91+
92+
const result = findDefaultSdkInitFile('client', nuxtMock);
93+
expect(result).toMatch('packages/nuxt/sentry.client.config.ts');
94+
});
95+
96+
it('should return the latest layer config file path if server config exists', () => {
97+
vi.spyOn(fs, 'existsSync').mockImplementation(filePath => {
98+
return (
99+
!(filePath instanceof URL) &&
100+
(filePath.includes('sentry.server.config.ts') || filePath.includes('instrument.server.ts'))
101+
);
102+
});
103+
104+
const nuxtMock = {
105+
options: {
106+
_layers: [
107+
{
108+
cwd: 'packages/nuxt/module',
109+
},
110+
{
111+
cwd: 'packages/nuxt',
112+
},
113+
],
114+
},
115+
} as Nuxt;
116+
117+
const result = findDefaultSdkInitFile('server', nuxtMock);
118+
expect(result).toMatch('packages/nuxt/sentry.server.config.ts');
119+
});
120+
121+
it('should return the latest layer config file path if client config exists in former layer', () => {
122+
vi.spyOn(fs, 'existsSync').mockImplementation(filePath => {
123+
return !(filePath instanceof URL) && filePath.includes('nuxt/sentry.client.config.ts');
124+
});
125+
126+
const nuxtMock = {
127+
options: {
128+
_layers: [
129+
{
130+
cwd: 'packages/nuxt/module',
131+
},
132+
{
133+
cwd: 'packages/nuxt',
134+
},
135+
],
136+
},
137+
} as Nuxt;
138+
139+
const result = findDefaultSdkInitFile('client', nuxtMock);
140+
expect(result).toMatch('packages/nuxt/sentry.client.config.ts');
141+
});
72142
});
73143

74144
describe('getFilenameFromPath', () => {

0 commit comments

Comments
 (0)