Skip to content

Commit 079a46b

Browse files
authored
feat(nuxt): Add base boilerplate for nuxt (#12573)
Boilerplate which adds a basic wrapper around the vue SDK. Still a lot WIP. closes #12572
1 parent cfe07f4 commit 079a46b

24 files changed

+3911
-144
lines changed

dev-packages/e2e-tests/verdaccio-config/config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,12 @@ packages:
170170
unpublish: $all
171171
# proxy: npmjs # Don't proxy for E2E tests!
172172

173+
'@sentry/nuxt':
174+
access: $all
175+
publish: $all
176+
unpublish: $all
177+
# proxy: npmjs # Don't proxy for E2E tests!
178+
173179
'@sentry/wasm':
174180
access: $all
175181
publish: $all

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"packages/integration-shims",
6363
"packages/nextjs",
6464
"packages/node",
65+
"packages/nuxt",
6566
"packages/opentelemetry",
6667
"packages/profiling-node",
6768
"packages/react",

packages/nuxt/.eslintrc.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
module.exports = {
2+
env: {
3+
browser: true,
4+
node: true,
5+
},
6+
overrides: [
7+
{
8+
files: ['vite.config.ts'],
9+
parserOptions: {
10+
project: ['tsconfig.test.json'],
11+
},
12+
},
13+
{
14+
files: ['src/vite/**', 'src/server/**'],
15+
rules: {
16+
'@sentry-internal/sdk/no-optional-chaining': 'off',
17+
},
18+
},
19+
],
20+
extends: ['../../.eslintrc.js'],
21+
};

packages/nuxt/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023-2024 Functional Software, Inc. dba Sentry
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
this software and associated documentation files (the "Software"), to deal in
7+
the Software without restriction, including without limitation the rights to
8+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9+
of the Software, and to permit persons to whom the Software is furnished to do
10+
so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/nuxt/README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<p align="center">
2+
<a href="https://sentry.io/?utm_source=github&utm_medium=logo" target="_blank">
3+
<img src="https://sentry-brand.storage.googleapis.com/sentry-wordmark-dark-280x84.png" alt="Sentry" width="280" height="84">
4+
</a>
5+
</p>
6+
7+
# Official Sentry SDK for Nuxt (EXPERIMENTAL)
8+
9+
[![npm version](https://img.shields.io/npm/v/@sentry/nuxt.svg)](https://www.npmjs.com/package/@sentry/nuxt)
10+
[![npm dm](https://img.shields.io/npm/dm/@sentry/nuxt.svg)](https://www.npmjs.com/package/@sentry/nuxt)
11+
[![npm dt](https://img.shields.io/npm/dt/@sentry/nuxt.svg)](https://www.npmjs.com/package/@sentry/nuxt)
12+
13+
**This SDK is under active development and not yet published!**
14+
15+
## Links
16+
17+
todo: link official SDK docs
18+
19+
- [Official SDK Docs](https://docs.sentry.io/platforms/javascript/)
20+
21+
## Compatibility
22+
23+
The minimum supported version of Nuxt is `3.0.0`.
24+
25+
## General
26+
27+
This package is a wrapper around `@sentry/node` for the server and `@sentry/vue` for the client side, with added
28+
functionality related to Nuxt.
29+
30+
## Automatic Setup
31+
32+
todo: add wizard instructions
33+
34+
Take a look at the sections below if you want to customize your SDK configuration.
35+
36+
## Manual Setup
37+
38+
If the setup through the wizard doesn't work for you, you can also set up the SDK manually.
39+
40+
### 1. Prerequesits & Installation
41+
42+
1. Install the Sentry Nuxt SDK:
43+
44+
```bash
45+
# Using npm
46+
npm install @sentry/nuxt
47+
48+
# Using yarn
49+
yarn add @sentry/nuxt
50+
```
51+
52+
### 2. Client-side Setup
53+
54+
The Sentry Nuxt SDK is based on [Nuxt Modules](https://nuxt.com/docs/api/kit/modules).
55+
56+
1. Add `@sentry/nuxt` to the modules section of `nuxt.config.ts`:
57+
58+
```javascript
59+
// nuxt.config.ts
60+
export default defineNuxtConfig({
61+
modules: ['@sentry/nuxt'],
62+
runtimeConfig: {
63+
public: {
64+
sentry: {
65+
dsn: env.DSN,
66+
// Additional config
67+
},
68+
},
69+
},
70+
});
71+
```
72+
73+
### 3. Server-side Setup
74+
75+
todo: add server-side setup
76+
77+
### 4. Vite Setup
78+
79+
todo: add vite setup
80+
81+
---
82+
83+
## Uploading Source Maps
84+
85+
todo: add source maps instructions

packages/nuxt/package.json

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"name": "@sentry/nuxt",
3+
"version": "8.10.0",
4+
"description": "Official Sentry SDK for Nuxt (EXPERIMENTAL)",
5+
"repository": "git://github.com/getsentry/sentry-javascript.git",
6+
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/nuxt",
7+
"author": "Sentry",
8+
"license": "MIT",
9+
"engines": {
10+
"node": ">=16"
11+
},
12+
"files": [
13+
"build"
14+
],
15+
"main": "build/module.cjs",
16+
"module": "build/module.mjs",
17+
"types": "build/types.d.ts",
18+
"exports": {
19+
".": {
20+
"types": "./build/types.d.ts",
21+
"import": "./build/module.mjs",
22+
"require": "./build/module.cjs"
23+
},
24+
"./package.json": "./package.json"
25+
},
26+
"publishConfig": {
27+
"access": "public"
28+
},
29+
"peerDependencies": {
30+
"nuxt": "3.x"
31+
},
32+
"dependencies": {
33+
"@sentry/core": "8.10.0",
34+
"@sentry/node": "8.10.0",
35+
"@sentry/opentelemetry": "8.10.0",
36+
"@sentry/types": "8.10.0",
37+
"@sentry/utils": "8.10.0",
38+
"@sentry/vite-plugin": "2.18.0",
39+
"@sentry/vue": "8.10.0",
40+
"@nuxt/kit": "^3.12.2"
41+
},
42+
"devDependencies": {
43+
"@nuxt/module-builder": "0.8.0",
44+
"nuxt": "^3.12.2"
45+
},
46+
"scripts": {
47+
"build": "run-p build:transpile",
48+
"build:dev": "yarn build",
49+
"build:transpile": "nuxt-module-build build --outDir build",
50+
"build:watch": "run-p build:transpile:watch build:types:watch",
51+
"build:dev:watch": "yarn build:watch",
52+
"build:transpile:watch": "nuxt-module-build build --outDir build --watch",
53+
"build:types:watch": "tsc -p tsconfig.types.json --watch",
54+
"build:tarball": "ts-node ../../scripts/prepack.ts && npm pack ./build",
55+
"circularDepCheck": "madge --circular src/index.client.ts && madge --circular src/index.server.ts && madge --circular src/index.types.ts",
56+
"clean": "rimraf build coverage sentry-nuxt-*.tgz",
57+
"fix": "eslint . --format stylish --fix",
58+
"lint": "eslint . --format stylish",
59+
"test": "yarn test:unit",
60+
"test:unit": "vitest run",
61+
"test:watch": "vitest --watch",
62+
"yalc:publish": "ts-node ../../scripts/prepack.ts && yalc publish build --push --sig"
63+
},
64+
"volta": {
65+
"extends": "../../package.json"
66+
},
67+
"nx": {
68+
"targets": {
69+
"build:transpile": {
70+
"dependsOn": [
71+
"^build:transpile",
72+
"^build:types"
73+
],
74+
"outputs": [
75+
"{projectRoot}/build"
76+
]
77+
}
78+
}
79+
}
80+
}

packages/nuxt/src/client/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from '@sentry/vue';
2+
3+
export { init } from './sdk';

packages/nuxt/src/client/sdk.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { applySdkMetadata } from '@sentry/core';
2+
import type { Client } from '@sentry/types';
3+
import { init as initVue } from '@sentry/vue';
4+
import type { SentryVueOptions } from '../common/types';
5+
6+
/**
7+
* Initializes the client-side of the Nuxt SDK
8+
*
9+
* @param options Configuration options for the SDK.
10+
*/
11+
export function init(options: SentryVueOptions): Client | undefined {
12+
const sentryOptions = {
13+
...options,
14+
};
15+
16+
applySdkMetadata(sentryOptions, 'nuxt', ['nuxt', 'vue']);
17+
18+
return initVue(sentryOptions);
19+
}

packages/nuxt/src/common/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import type { init } from '@sentry/vue';
2+
3+
export type SentryVueOptions = Parameters<typeof init>[0] & object;

packages/nuxt/src/index.client.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './client';

packages/nuxt/src/index.server.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

packages/nuxt/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};

packages/nuxt/src/module.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { type Resolver, addPlugin, createResolver, defineNuxtModule } from '@nuxt/kit';
2+
import type { SentryVueOptions } from './common/types';
3+
4+
export type ModuleOptions = SentryVueOptions;
5+
6+
export default defineNuxtModule<ModuleOptions>({
7+
meta: {
8+
name: '@sentry/nuxt',
9+
configKey: 'sentry',
10+
compatibility: {
11+
nuxt: '^3.0.0',
12+
},
13+
},
14+
// Default configuration options of the Nuxt module
15+
defaults: {},
16+
setup(_moduleOptions, _nuxt) {
17+
const resolver: Resolver = createResolver(import.meta.url);
18+
19+
if (resolver) {
20+
addPlugin(resolver.resolve('runtime/plugins/sentry.client.js'));
21+
}
22+
},
23+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineNuxtPlugin, useRuntimeConfig } from 'nuxt/app';
2+
import { init } from '../../client';
3+
4+
export default defineNuxtPlugin(nuxtApp => {
5+
const config = useRuntimeConfig();
6+
const sentryConfig = config.public.sentry || {};
7+
8+
init({
9+
...sentryConfig,
10+
app: nuxtApp.vueApp,
11+
});
12+
});

packages/nuxt/test/client/sdk.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { SDK_VERSION } from '@sentry/vue';
2+
import * as SentryVue from '@sentry/vue';
3+
import { beforeEach, describe, expect, it, vi } from 'vitest';
4+
import { init } from '../../src/client';
5+
6+
const vueInit = vi.spyOn(SentryVue, 'init');
7+
8+
describe('Nuxt Client SDK', () => {
9+
describe('init', () => {
10+
beforeEach(() => {
11+
vi.clearAllMocks();
12+
});
13+
14+
it('Adds Nuxt metadata to the SDK options', () => {
15+
expect(vueInit).not.toHaveBeenCalled();
16+
17+
init({
18+
dsn: 'https://[email protected]/1337',
19+
});
20+
21+
const expectedMetadata = {
22+
_metadata: {
23+
sdk: {
24+
name: 'sentry.javascript.nuxt',
25+
version: SDK_VERSION,
26+
packages: [
27+
{ name: 'npm:@sentry/nuxt', version: SDK_VERSION },
28+
{ name: 'npm:@sentry/vue', version: SDK_VERSION },
29+
],
30+
},
31+
},
32+
};
33+
34+
expect(vueInit).toHaveBeenCalledTimes(1);
35+
expect(vueInit).toHaveBeenLastCalledWith(expect.objectContaining(expectedMetadata));
36+
});
37+
38+
it('returns client from init', () => {
39+
expect(init({})).not.toBeUndefined();
40+
});
41+
});
42+
});

packages/nuxt/test/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../tsconfig.test.json"
3+
}

packages/nuxt/test/vitest.setup.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function setup() {}
2+
3+
if (!globalThis.fetch) {
4+
// @ts-expect-error - Needed for vitest to work with our fetch instrumentation
5+
globalThis.Request = class Request {};
6+
// @ts-expect-error - Needed for vitest to work with our fetch instrumentation
7+
globalThis.Response = class Response {};
8+
}

packages/nuxt/tsconfig.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "../../tsconfig.json",
3+
4+
"include": ["src/**/*"],
5+
6+
"compilerOptions": {
7+
// package-specific options
8+
"module": "esnext"
9+
}
10+
}

packages/nuxt/tsconfig.test.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
4+
"include": ["test/**/*", "vite.config.ts"],
5+
6+
"compilerOptions": {
7+
// should include all types from `./tsconfig.json` plus types for all test frameworks used
8+
"types": ["node", "vitest/globals"]
9+
}
10+
}

packages/nuxt/tsconfig.types.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
4+
"compilerOptions": {
5+
"declaration": true,
6+
"declarationMap": true,
7+
"emitDeclarationOnly": true,
8+
"outDir": "build/types"
9+
}
10+
}

0 commit comments

Comments
 (0)