Skip to content

Commit

Permalink
feat(vue): Expose initVueApp method to initialize vue app later
Browse files Browse the repository at this point in the history
  • Loading branch information
mydea committed Oct 5, 2023
1 parent 945d873 commit c8fcfe8
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 14 deletions.
2 changes: 1 addition & 1 deletion packages/vue/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from '@sentry/browser';

export { init } from './sdk';
export { init, initVueApp } from './sdk';
export { vueRouterInstrumentation } from './router';
export { attachErrorHandler } from './errorhandler';
export { createTracingMixins } from './tracing';
22 changes: 19 additions & 3 deletions packages/vue/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { init as browserInit, SDK_VERSION } from '@sentry/browser';
import { hasTracingEnabled } from '@sentry/core';
import { arrayify, GLOBAL_OBJ } from '@sentry/utils';
import { getCurrentHub, hasTracingEnabled } from '@sentry/core';
import { arrayify, GLOBAL_OBJ, logger } from '@sentry/utils';

import { DEFAULT_HOOKS } from './constants';
import { attachErrorHandler } from './errorhandler';
Expand Down Expand Up @@ -43,7 +43,7 @@ export function init(

browserInit(options);

if (!options.Vue && !options.app) {
if (!options.Vue && !options.app && options.app !== false) {
// eslint-disable-next-line no-console
console.warn(
`[@sentry/vue]: Misconfigured SDK. Vue specific errors will not be captured.
Expand All @@ -61,6 +61,22 @@ Update your \`Sentry.init\` call with an appropriate config option:
}
}

/**
* Initialize Vue-specific error monitoring for a given Vue app.
*/
export function initVueApp(app: Vue): void {
const client = getCurrentHub().getClient();
const options = client && (client.getOptions() as Options);

if (options) {
vueInit(app, options);
} else if (__DEBUG_BUILD__) {
logger.warn(
'[@sentry/vue]: Cannot initialize as no Client available. Make sure to call `Sentry.init` before calling `initVueApp()`.',
);
}
}

const vueInit = (app: Vue, options: Options): void => {
// Check app is not mounted yet - should be mounted _after_ init()!
// This is _somewhat_ private, but in the case that this doesn't exist we simply ignore it
Expand Down
8 changes: 6 additions & 2 deletions packages/vue/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ export interface Options extends TracingOptions, BrowserOptions {
/** Vue constructor to be used inside the integration (as imported by `import Vue from 'vue'` in Vue2) */
Vue?: Vue;

/** Vue app instance(s) to be used inside the integration (as generated by `createApp` in Vue3 ) */
app?: Vue | Vue[];
/**
* Vue app instance(s) to be used inside the integration (as generated by `createApp` in Vue3 )
* Set this to `false` to indicate you are purposefully _not_ setting up a Vue app right now,
* e.g. if you want to manually call `initVueApp` later.
*/
app?: Vue | Vue[] | false;

/**
* When set to `false`, Sentry will suppress reporting of all props data
Expand Down
27 changes: 19 additions & 8 deletions packages/vue/test/integration/init.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,17 @@ import { createApp } from 'vue';
import * as Sentry from './../../src';

describe('Sentry.init', () => {
let _consoleWarn: any;
let warnings: string[] = [];
let warnings: unknown[] = [];

beforeEach(() => {
warnings = [];
// eslint-disable-next-line no-console
_consoleWarn = console.warn;
// eslint-disable-next-line no-console
console.warn = jest.fn((message: string) => {
jest.spyOn(console, 'warn').mockImplementation((message: unknown) => {
warnings.push(message);
});
});

afterEach(() => {
// eslint-disable-next-line no-console
console.warn = _consoleWarn;
jest.clearAllMocks();
});

it('does not warn when correctly setup (Vue 3)', () => {
Expand Down Expand Up @@ -90,4 +85,20 @@ Update your \`Sentry.init\` call with an appropriate config option:
\`app\` (Application Instance - Vue 3) or \`Vue\` (Vue Constructor - Vue 2).`,
]);
});

it('does not warn when passing app=false', () => {
const el = document.createElement('div');
const app = createApp({
template: '<div>hello</div>',
});

Sentry.init({
app: false,
defaultIntegrations: false,
});

app.mount(el);

expect(warnings).toEqual([]);
});
});
81 changes: 81 additions & 0 deletions packages/vue/test/integration/initVueApp.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { logger } from '@sentry/utils';
import { createApp } from 'vue';

import * as Sentry from '../../src';
import { Hub, makeMain } from '../../src';

const PUBLIC_DSN = 'https://username@domain/123';

describe('Sentry.initVueApp', () => {
let loggerWarnings: unknown[] = [];
let warnings: unknown[] = [];

beforeEach(() => {
warnings = [];
loggerWarnings = [];

jest.spyOn(logger, 'warn').mockImplementation((message: unknown) => {
loggerWarnings.push(message);
});

jest.spyOn(console, 'warn').mockImplementation((message: unknown) => {
warnings.push(message);
});
});

afterEach(() => {
jest.resetAllMocks();
});

it('warns when called before SDK.init()', () => {
const hub = new Hub();
makeMain(hub);

const app = createApp({
template: '<div>hello</div>',
});

Sentry.initVueApp(app);

expect(loggerWarnings).toEqual([
'[@sentry/vue]: Cannot initialize as no Client available. Make sure to call `Sentry.init` before calling `initVueApp()`.',
]);
expect(warnings).toEqual([]);
});

it('warns when mounting before SDK.initVueApp()', () => {
Sentry.init({ dsn: PUBLIC_DSN, app: false, autoSessionTracking: false });

const el = document.createElement('div');
const app = createApp({
template: '<div>hello</div>',
});

app.mount(el);

Sentry.initVueApp(app);

expect(warnings).toEqual([
'[@sentry/vue]: Misconfigured SDK. Vue app is already mounted. Make sure to call `app.mount()` after `Sentry.init()`.',
]);
expect(loggerWarnings).toEqual([]);
});

it('works when calling SDK.initVueApp()', () => {
Sentry.init({ dsn: PUBLIC_DSN, app: false, autoSessionTracking: false });

const el = document.createElement('div');
const app = createApp({
template: '<div>hello</div>',
});

Sentry.initVueApp(app);

app.mount(el);

expect(warnings).toEqual([]);
expect(loggerWarnings).toEqual([]);

expect(app.config.errorHandler).toBeDefined();
});
});

0 comments on commit c8fcfe8

Please sign in to comment.