From 2a1106006e1f28b2dafbe12e5b327129d8df8cc3 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 17 Nov 2022 15:49:49 +0100 Subject: [PATCH 1/2] feat(vue): Check if SDK is initialized before app is mounted --- packages/vue/package.json | 3 + packages/vue/src/sdk.ts | 17 +++ packages/vue/test/integration/init.test.ts | 74 ++++++++++++ yarn.lock | 126 ++++++++++++++++++++- 4 files changed, 217 insertions(+), 3 deletions(-) create mode 100644 packages/vue/test/integration/init.test.ts diff --git a/packages/vue/package.json b/packages/vue/package.json index 45da4af2e076..9e8d6e4764ac 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -25,6 +25,9 @@ "peerDependencies": { "vue": "2.x || 3.x" }, + "devDependencies": { + "vue": "~3.2.41" + }, "scripts": { "build": "run-p build:rollup build:types", "build:bundle": "yarn ts-node ../../scripts/ensure-bundle-deps.ts && yarn rollup --config rollup.bundle.config.js", diff --git a/packages/vue/src/sdk.ts b/packages/vue/src/sdk.ts index 2d9030674309..f6513676621c 100644 --- a/packages/vue/src/sdk.ts +++ b/packages/vue/src/sdk.ts @@ -61,6 +61,23 @@ export function init( } 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 + // See: https://github.com/vuejs/core/blob/eb2a83283caa9de0a45881d860a3cbd9d0bdd279/packages/runtime-core/src/component.ts#L394 + const appWithInstance = app as Vue & { + _instance?: { + isMounted?: boolean; + }; + }; + + const isMounted = appWithInstance._instance && appWithInstance._instance.isMounted; + if (isMounted === true) { + // eslint-disable-next-line no-console + console.warn( + '[@sentry/vue]: Misconfigured SDK. Vue app is already mounted. Make sure to call `app.mount()` after `Sentry.init()`.', + ); + } + attachErrorHandler(app, options); if ('tracesSampleRate' in options || 'tracesSampler' in options) { diff --git a/packages/vue/test/integration/init.test.ts b/packages/vue/test/integration/init.test.ts new file mode 100644 index 000000000000..7723c92233ef --- /dev/null +++ b/packages/vue/test/integration/init.test.ts @@ -0,0 +1,74 @@ +import { createApp } from 'vue'; + +import * as Sentry from './../../src'; + +describe('Sentry.init', () => { + let _consoleWarn: any; + let warnings: string[] = []; + + beforeEach(() => { + warnings = []; + // eslint-disable-next-line no-console + _consoleWarn = console.warn; + // eslint-disable-next-line no-console + console.warn = jest.fn((message: string) => { + warnings.push(message); + }); + }); + + afterEach(() => { + // eslint-disable-next-line no-console + console.warn = _consoleWarn; + }); + + it('does not warn when correctly setup (Vue 3)', () => { + const el = document.createElement('div'); + const app = createApp({ + template: '
hello
', + }); + + Sentry.init({ + app, + defaultIntegrations: false, + }); + + app.mount(el); + + expect(warnings).toEqual([]); + }); + + it('does not warn when correctly setup (Vue 2)', () => { + const el = document.createElement('div'); + const app = createApp({ + template: '
hello
', + }); + + Sentry.init({ + // this is a bit "hacky", but good enough to test what we want + Vue: app, + defaultIntegrations: false, + }); + + app.mount(el); + + expect(warnings).toEqual([]); + }); + + it('warns when mounting before SDK init', () => { + const el = document.createElement('div'); + const app = createApp({ + template: '
hello
', + }); + + app.mount(el); + + Sentry.init({ + app, + defaultIntegrations: false, + }); + + expect(warnings).toEqual([ + '[@sentry/vue]: Misconfigured SDK. Vue app is already mounted. Make sure to call `app.mount()` after `Sentry.init()`.', + ]); + }); +}); diff --git a/yarn.lock b/yarn.lock index 33dcafb96c09..5246d1c54bbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -843,6 +843,11 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== +"@babel/parser@^7.16.4": + version "7.20.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.3.tgz#5358cf62e380cf69efcb87a7bb922ff88bfac6e2" + integrity sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg== + "@babel/parser@^7.18.10", "@babel/parser@^7.19.6": version "7.19.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.19.6.tgz#b923430cb94f58a7eae8facbffa9efd19130e7f8" @@ -5497,6 +5502,96 @@ "@typescript-eslint/types" "4.23.0" eslint-visitor-keys "^2.0.0" +"@vue/compiler-core@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.45.tgz#d9311207d96f6ebd5f4660be129fb99f01ddb41b" + integrity sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + source-map "^0.6.1" + +"@vue/compiler-dom@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz#c43cc15e50da62ecc16a42f2622d25dc5fd97dce" + integrity sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw== + dependencies: + "@vue/compiler-core" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/compiler-sfc@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz#7f7989cc04ec9e7c55acd406827a2c4e96872c70" + integrity sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.45" + "@vue/compiler-dom" "3.2.45" + "@vue/compiler-ssr" "3.2.45" + "@vue/reactivity-transform" "3.2.45" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + magic-string "^0.25.7" + postcss "^8.1.10" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz#bd20604b6e64ea15344d5b6278c4141191c983b2" + integrity sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ== + dependencies: + "@vue/compiler-dom" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/reactivity-transform@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz#07ac83b8138550c83dfb50db43cde1e0e5e8124d" + integrity sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ== + dependencies: + "@babel/parser" "^7.16.4" + "@vue/compiler-core" "3.2.45" + "@vue/shared" "3.2.45" + estree-walker "^2.0.2" + magic-string "^0.25.7" + +"@vue/reactivity@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.45.tgz#412a45b574de601be5a4a5d9a8cbd4dee4662ff0" + integrity sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A== + dependencies: + "@vue/shared" "3.2.45" + +"@vue/runtime-core@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.45.tgz#7ad7ef9b2519d41062a30c6fa001ec43ac549c7f" + integrity sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A== + dependencies: + "@vue/reactivity" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/runtime-dom@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz#1a2ef6ee2ad876206fbbe2a884554bba2d0faf59" + integrity sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA== + dependencies: + "@vue/runtime-core" "3.2.45" + "@vue/shared" "3.2.45" + csstype "^2.6.8" + +"@vue/server-renderer@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.45.tgz#ca9306a0c12b0530a1a250e44f4a0abac6b81f3f" + integrity sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g== + dependencies: + "@vue/compiler-ssr" "3.2.45" + "@vue/shared" "3.2.45" + +"@vue/shared@3.2.45": + version "3.2.45" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.45.tgz#a3fffa7489eafff38d984e23d0236e230c818bc2" + integrity sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg== + "@web3-storage/multipart-parser@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@web3-storage/multipart-parser/-/multipart-parser-1.0.0.tgz#6b69dc2a32a5b207ba43e556c25cc136a56659c4" @@ -10074,6 +10169,11 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +csstype@^2.6.8: + version "2.6.21" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e" + integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w== + csstype@^3.0.2: version "3.0.7" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" @@ -12189,7 +12289,7 @@ estree-walker@^1.0.1: resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== -estree-walker@^2.0.1: +estree-walker@^2.0.1, estree-walker@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== @@ -18333,7 +18433,7 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19" integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ== -nanoid@^3.1.16, nanoid@^3.1.20, nanoid@^3.1.30: +nanoid@^3.1.16, nanoid@^3.1.20, nanoid@^3.1.30, nanoid@^3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab" integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw== @@ -20544,6 +20644,15 @@ postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.2, postcss@^7.0.27 picocolors "^0.2.1" source-map "^0.6.1" +postcss@^8.1.10: + version "8.4.19" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" + integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + postcss@^8.1.7, postcss@^8.2.15: version "8.4.4" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" @@ -22927,7 +23036,7 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1: +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== @@ -25235,6 +25344,17 @@ void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w= +vue@~3.2.41: + version "3.2.45" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8" + integrity sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA== + dependencies: + "@vue/compiler-dom" "3.2.45" + "@vue/compiler-sfc" "3.2.45" + "@vue/runtime-dom" "3.2.45" + "@vue/server-renderer" "3.2.45" + "@vue/shared" "3.2.45" + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" From bf67f18d4a56f4f42768cd0eb3103236cffd2d74 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 18 Nov 2022 10:15:08 +0100 Subject: [PATCH 2/2] feat(vue): Actually `console.warn` when not passing app/Vue --- packages/vue/src/sdk.ts | 14 +++++++------- packages/vue/test/integration/init.test.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/packages/vue/src/sdk.ts b/packages/vue/src/sdk.ts index f6513676621c..a2063038402c 100644 --- a/packages/vue/src/sdk.ts +++ b/packages/vue/src/sdk.ts @@ -1,5 +1,5 @@ import { init as browserInit, SDK_VERSION } from '@sentry/browser'; -import { arrayify, GLOBAL_OBJ, logger } from '@sentry/utils'; +import { arrayify, GLOBAL_OBJ } from '@sentry/utils'; import { DEFAULT_HOOKS } from './constants'; import { attachErrorHandler } from './errorhandler'; @@ -43,12 +43,12 @@ export function init( browserInit(options); if (!options.Vue && !options.app) { - __DEBUG_BUILD__ && - logger.warn( - 'Misconfigured SDK. Vue specific errors will not be captured.\n' + - 'Update your `Sentry.init` call with an appropriate config option:\n' + - '`app` (Application Instance - Vue 3) or `Vue` (Vue Constructor - Vue 2).', - ); + // eslint-disable-next-line no-console + console.warn( + `[@sentry/vue]: Misconfigured SDK. Vue specific errors will not be captured. +Update your \`Sentry.init\` call with an appropriate config option: +\`app\` (Application Instance - Vue 3) or \`Vue\` (Vue Constructor - Vue 2).`, + ); return; } diff --git a/packages/vue/test/integration/init.test.ts b/packages/vue/test/integration/init.test.ts index 7723c92233ef..a9936c97bc89 100644 --- a/packages/vue/test/integration/init.test.ts +++ b/packages/vue/test/integration/init.test.ts @@ -71,4 +71,23 @@ describe('Sentry.init', () => { '[@sentry/vue]: Misconfigured SDK. Vue app is already mounted. Make sure to call `app.mount()` after `Sentry.init()`.', ]); }); + + it('warns when not passing app & Vue', () => { + const el = document.createElement('div'); + const app = createApp({ + template: '
hello
', + }); + + Sentry.init({ + defaultIntegrations: false, + }); + + app.mount(el); + + expect(warnings).toEqual([ + `[@sentry/vue]: Misconfigured SDK. Vue specific errors will not be captured. +Update your \`Sentry.init\` call with an appropriate config option: +\`app\` (Application Instance - Vue 3) or \`Vue\` (Vue Constructor - Vue 2).`, + ]); + }); });