🚨 Latest Research:Tanstack npm Packages Compromised in Ongoing Mini Shai-Hulud Supply-Chain Attack.Learn More
Socket
Book a DemoSign in
Socket

@nuxtjs/sentry

Package Overview
Dependencies
Maintainers
7
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nuxtjs/sentry - npm Package Compare versions

Comparing version
4.1.3
to
4.2.0
+32
lib/plugin.client.js
import VueLib from 'vue'
import * as Sentry from '@sentry/browser'
<% if (options.initialize) { %>
import { <%= Object.keys(options.integrations).join(', ') %> } from '@sentry/integrations'
<% } %>
export default function (ctx, inject) {
<% if (options.initialize) { %>
/* eslint-disable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
const config = <%= serialize(options.config) %>
config.integrations = [
<%= Object.entries(options.integrations).map(([name, integration]) => {
if (name === 'Vue') {
return `new ${name}({ Vue: VueLib, ...${serialize(integration)}})`
}
const integrationOptions = Object.entries(integration).map(([key, option]) => {
typeof option === 'function'
? `${key}:${serializeFunction(option)}`
: `${key}:${serialize(option)}`
})
return `new ${name}({${integrationOptions.join(',')}})`
}).join(',\n ')%>
]
/* eslint-enable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
Sentry.init(config)
<% } %>
inject('sentry', Sentry)
ctx.$sentry = Sentry
}
import VueLib from 'vue'
<% if (options.lazy.injectMock) { %>
/* eslint-enable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
let delayedCalls = []
let SentryMock = {}
<% } %>
let sentryReadyResolve
let loadInitiated = false
<% if (options.lazy.injectMock) { %>
let loadCompleted = false
const vueErrorHandler = VueLib.config.errorHandler
VueLib.config.errorHandler = (error, vm, info) => {
if (!loadCompleted) {
vm.$sentry.captureException(error)
if (VueLib.util) {
VueLib.util.warn(`Error in ${info}: "${error.toString()}"`, vm)
}
console.error(error) // eslint-disable-line no-console
}
if (vueErrorHandler) {
return vueErrorHandler(error, vm, info)
}
}
<% } %>
export default function SentryPlugin (ctx, inject) {
<% if (options.lazy.injectMock) { %>
/* eslint-disable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
const apiMethods = <%= JSON.stringify(options.lazy.mockApiMethods)%>
apiMethods.forEach((key) => {
SentryMock[key] = (...args) => delayedCalls.push([key, args])
})
window.addEventListener('error', SentryMock.captureException)
inject('sentry', SentryMock)
ctx.$sentry = SentryMock
<% } %>
const loadSentryHook = () => !loadInitiated && loadSentry(ctx, inject)
<% if (options.lazy.injectLoadHook) { %>
inject('sentryLoad', loadSentryHook)
ctx.$sentryLoad = loadSentryHook
<% } else { %>
window.<%= globals.readyCallback %>(loadSentryHook)
<% } %>
const sentryReadyPromise = new Promise((resolve) => {
sentryReadyResolve = resolve
})
const sentryReady = () => sentryReadyPromise
inject('sentryReady', sentryReady)
ctx.$sentryReady = sentryReady
}
async function loadSentry (ctx, inject) {
loadInitiated = true
if (!window.<%= globals.nuxt %>) {
<% if (options.dev) { %>
// eslint-disable-next-line no-console
console.warn(`$sentryLoad was called but window.<%= globals.nuxt %> is not available, delaying sentry loading until onNuxtReady callback. Do you really need to use lazy loading for Sentry?`)
<% } %>
window.<%= globals.readyCallback %>(() => loadSentry(ctx, inject))
return
}
<%
const magicComments = [`webpackChunkName: '${options.lazy.chunkName}'`]
if (options.lazy.webpackPrefetch) {
magicComments.push('webpackPrefetch: true')
}
if (options.lazy.webpackPreload) {
magicComments.push('webpackPreload: true')
}
%>
const Sentry = await import(/* <%= magicComments.join(', ') %> */ '@sentry/browser')
<% if (options.initialize) { %>// Initialize sentry
const { <%= Object.keys(options.integrations).join(', ') %> } = await import(/* <%= magicComments.join(', ') %> */ '@sentry/integrations')
/* eslint-disable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
const config = <%= serialize(options.config) %>
config.integrations = [
<%= Object.entries(options.integrations).map(([name, integration]) => {
if (name === 'Vue') {
return `new ${name}({ Vue: VueLib, ...${serialize(integration)}})`
}
const integrationOptions = Object.entries(integration).map(([key, option]) =>
typeof option === 'function'
? `${key}:${serializeFunction(option)}`
: `${key}:${serialize(option)}`
)
return `new ${name}({${integrationOptions.join(',')}})`
}).join(',\n ')%>
]
/* eslint-enable object-curly-spacing, quote-props, quotes, key-spacing, comma-spacing */
Sentry.init(config)
<% } %>
<% if (options.lazy.injectMock) { %>
loadCompleted = true
window.removeEventListener('error', SentryMock.captureException)
delayedCalls.forEach(([methodName, args]) => Sentry[methodName].apply(Sentry, args))
<% } %>
forceInject(ctx, inject, 'sentry', Sentry)
sentryReadyResolve(Sentry)
// help gc
<% if (options.lazy.injectMock) { %>
// Dont unset delayedCalls & SentryMock during
// development, this will cause HMR issues
<% if (!options.dev) { %>
delayedCalls = undefined
SentryMock = undefined
<% } else { %>
delayedCalls = []
<% } %>
<% } %>
sentryReadyResolve = undefined
}
// Custom inject function that is able to overwrite previously injected values,
// which original inject doesn't allow to do.
// This method is adapted from the inject method in nuxt/vue-app/template/index.js
function forceInject (ctx, inject, key, value) {
inject(key, value)
const injectKey = '$' + key
ctx[injectKey] = value
window.<%= globals.nuxt %>.$options[injectKey] = value
}
const apiMethods = <%= JSON.stringify(options.apiMethods)%>
/** @type {import('@nuxt/types').Plugin} */
export default function (ctx, inject) {
const SentryMock = {}
apiMethods.forEach(key => {
// eslint-disable-next-line no-console
SentryMock[key] = <%= options.logMockCalls
? '(...args) => console.warn(`$sentry.${key}() called, but Sentry plugin is disabled. Arguments:`, args)'
: '_ => _'%>
})
// Inject mocked sentry to the context as $sentry (this is used in case sentry is disabled)
inject('sentry', SentryMock)
ctx.$sentry = SentryMock
}
/** @type {import('@nuxt/types').Module} */
export default function (ctx, inject) {
const sentry = process.sentry || {}
inject('sentry', sentry)
ctx.$sentry = sentry
<% if (options.lazy) { %>
const sentryReady = () => Promise.resolve(sentry)
inject('sentryReady', sentryReady)
ctx.$sentryReady = sentryReady
<% } %>
}
+7
-0

@@ -0,1 +1,8 @@

## [4.2.0](https://github.com/nuxt-community/sentry-module/compare/v4.1.3...v4.2.0) (2020-07-27)
### Features
* support lazy loading of Sentry on the client ([#198](https://github.com/nuxt-community/sentry-module/issues/198)) ([963fead](https://github.com/nuxt-community/sentry-module/commit/963fead523d94661dfc4c597866db66408b7a667)), closes [#127](https://github.com/nuxt-community/sentry-module/issues/127)
### [4.1.3](https://github.com/nuxt-community/sentry-module/compare/v4.1.2...v4.1.3) (2020-07-01)

@@ -2,0 +9,0 @@

+95
-37

@@ -14,4 +14,5 @@ import { resolve, posix } from 'path'

/** @type {import('@nuxt/types').Module} */
export default function SentryModule (moduleOptions) {
export default async function SentryModule (moduleOptions) {
const defaults = {
lazy: false,
dsn: process.env.SENTRY_DSN || false,

@@ -99,34 +100,77 @@ disabled: process.env.SENTRY_DISABLED || false,

const apiMethods = await getBrowserApiMethods()
if (options.lazy) {
const defaultLazyOptions = {
injectMock: true,
injectLoadHook: false,
mockApiMethods: true,
chunkName: 'sentry',
webpackPrefetch: false,
webpackPreload: false
}
options.lazy = Object.assign({}, defaultLazyOptions, options.lazy)
if (!options.lazy.injectMock) {
options.lazy.mockApiMethods = []
} else if (options.lazy.mockApiMethods === true) {
options.lazy.mockApiMethods = apiMethods
} else if (Array.isArray(options.lazy.mockApiMethods)) {
const mockMethods = options.lazy.mockApiMethods
options.lazy.mockApiMethods = mockMethods.filter(method => apiMethods.includes(method))
const notfoundMethods = mockMethods.filter(method => !apiMethods.includes(method))
if (notfoundMethods.length) {
logger.warn('Some specified methods to mock weren\'t found in @sentry/browser:', notfoundMethods)
}
if (!options.lazy.mockApiMethods.includes('captureException')) {
// always add captureException if a sentry mock is requested
options.lazy.mockApiMethods.push('captureException')
}
}
}
const initializationRequired = options.initialize && options.dsn
// Register the client plugin
if (!options.disabled && !options.disableClientSide) {
this.addPlugin({
src: resolve(__dirname, 'sentry.client.js'),
fileName: 'sentry.client.js',
mode: 'client',
options: {
config: {
dsn: options.dsn,
...options.clientConfig
},
initialize: initializationRequired,
integrations: filterDisabledIntegration(options.clientIntegrations)
.reduce((res, key) => {
res[key] = options.clientIntegrations[key]
return res
}, {})
}
})
let pluginOptionClient
if (options.disabled || options.disableClientSide) {
pluginOptionClient = 'mocked'
} else if (options.lazy) {
pluginOptionClient = 'lazy'
} else {
this.addPlugin({
src: resolve(__dirname, 'sentry.mocked.js'),
fileName: 'sentry.client.js',
options: { logMockCalls: options.logMockCalls },
mode: 'client'
})
pluginOptionClient = 'client'
}
this.addPlugin({
src: resolve(__dirname, `plugin.${pluginOptionClient}.js`),
fileName: 'sentry.client.js',
mode: 'client',
options: {
dev: this.options.dev,
config: {
dsn: options.dsn,
...options.clientConfig
},
lazy: options.lazy,
apiMethods,
logMockCalls: options.logMockCalls, // for mocked only
initialize: initializationRequired,
integrations: filterDisabledIntegration(options.clientIntegrations)
.reduce((res, key) => {
res[key] = options.clientIntegrations[key]
return res
}, {})
}
})
// Register the server plugin
if (!options.disabled && !options.disableServerSide) {
let pluginOptionServer
if (options.disabled || options.disableServerSide) {
pluginOptionServer = 'mocked'
} else {
pluginOptionServer = 'server'
// Initialize Sentry

@@ -144,7 +188,2 @@ if (initializationRequired) {

this.addPlugin({
src: resolve(__dirname, 'sentry.server.js'),
fileName: 'sentry.server.js',
mode: 'server'
})
this.nuxt.hook('render:setupMiddleware', app => app.use(Sentry.Handlers.requestHandler()))

@@ -158,10 +197,16 @@ this.nuxt.hook('render:errorMiddleware', app => app.use(Sentry.Handlers.errorHandler()))

})
} else {
this.addPlugin({
src: resolve(__dirname, 'sentry.mocked.js'),
fileName: 'sentry.server.js',
mode: 'server'
})
}
this.addPlugin({
src: resolve(__dirname, `plugin.${pluginOptionServer}.js`),
fileName: 'sentry.server.js',
mode: 'server',
options: {
dev: this.options.dev,
lazy: options.lazy,
apiMethods,
logMockCalls: options.logMockCalls // for mocked only
}
})
const isLoggingEnabled = !options.disabled && options.dsn && options.initialize

@@ -206,1 +251,14 @@ const isClientEnabled = isLoggingEnabled && !options.disableClientSide

}
async function getBrowserApiMethods () {
const SentryBrowser = await import('@sentry/browser')
const browserMethods = []
for (const key in SentryBrowser) {
if (typeof SentryBrowser[key] === 'function') {
browserMethods.push(key)
}
}
return browserMethods
}
{
"name": "@nuxtjs/sentry",
"version": "4.1.3",
"version": "4.2.0",
"description": "Sentry module for Nuxt.js",

@@ -10,2 +10,5 @@ "repository": "nuxt-community/sentry-module",

"name": "Diederik van den Burger <diederik@webrelated.nl>"
},
{
"name": "Rafal Chlodnicki (@rchl)"
}

@@ -20,4 +23,6 @@ ],

"lint": "eslint --ext .vue,.js lib test types/**/*.ts",
"lint:fixture": "eslint --ext .vue,.js --no-ignore 'test/fixture/*/.nuxt/sentry.*'",
"release": "release-it",
"test": "yarn lint && jest"
"test:fixture": "jest --runInBand",
"test": "yarn lint --fix && yarn test:fixture && yarn lint:fixture"
},

@@ -41,6 +46,6 @@ "babel": {

"dependencies": {
"@sentry/browser": "^5.18.1",
"@sentry/integrations": "^5.18.1",
"@sentry/node": "^5.18.1",
"@sentry/webpack-plugin": "^1.11.1",
"@sentry/browser": "^5.20.1",
"@sentry/integrations": "^5.20.1",
"@sentry/node": "^5.20.1",
"@sentry/webpack-plugin": "^1.12.0",
"consola": "^2.14.0",

@@ -50,16 +55,17 @@ "deepmerge": "^4.2.2"

"devDependencies": {
"@babel/core": "^7.10.4",
"@babel/core": "^7.10.5",
"@babel/preset-env": "^7.10.4",
"@nuxt/types": "^2.13.2",
"@nuxt/types": "^2.13.3",
"@nuxtjs/eslint-config-typescript": "^2.0.0",
"@nuxtjs/module-test-utils": "^1.6.2",
"@nuxtjs/module-test-utils": "^1.6.3",
"@release-it/conventional-changelog": "^1.1.4",
"babel-core": "^7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.1.0",
"codecov": "^3.7.0",
"eslint": "^7.3.1",
"codecov": "^3.7.2",
"eslint": "^7.5.0",
"jest": "^26.1.0",
"nuxt-edge": "^2.11.1-26378723.c5d0067",
"release-it": "^13.6.4",
"typescript": "^3.9.5"
"release-it": "^13.6.6",
"typescript": "^3.9.7"
},

@@ -66,0 +72,0 @@ "publishConfig": {

+162
-8

@@ -20,2 +20,5 @@ # @nuxtjs/sentry

## Setup
> Nuxt.js v2.4.0+ is required, earlier versions are not supported
- Add `@nuxtjs/sentry` dependency using yarn or npm to your project

@@ -36,11 +39,11 @@ - Add `@nuxtjs/sentry` to `modules` section of `nuxt.config.js`

```
## Configure
### Nuxt compatibility
Versions of NuxtJS before v2.4.0 are **not** supported by this package.
See [Options](#options) for a list of available options
## Usage
Enter your DSN in the NuxtJS config file. Additional config settings can be found [here](https://docs.sentry.io/error-reporting/configuration/?platform=browser).
Enter your DSN in the Nuxt.js config file. Additional config settings can be found [here](https://docs.sentry.io/error-reporting/configuration/?platform=browser).
### Usage in Vue component
### Usage in Vue components

@@ -85,2 +88,58 @@ In a Vue component, `Sentry` is available as `this.$sentry`, so we can call functions like

## Lazy Loading (on the client)
> :warning: Please be aware that lazy loading could prevent some errors from being reported
Set `lazy: true` in your module options to load Sentry lazily on the client. This will prevent Sentry from being included in your main bundle **but could result in some errors not being reported**.
You can also pass a lazy config object in your module options (see [options](#lazy) for more information).
### Injected properties
#### `$sentry` (mocked)
- Type: `Object`
Normally `$sentry` would always refer to the `@sentry/browser` API. But if we lazy load Sentry this API wont be available until Sentry has loaded. If you don't want to worry about whether Sentry is loaded or not, a mocked Sentry API is injected into the Nuxt.js context that will execute all Sentry API calls once Sentry is loaded
See: `injectMock` and `mockApiMethods` options below
#### `$sentryReady`
- Type `Function`
This method returns a Promise which will be resolved once Sentry has been loaded. You could use this instead of mocking `$sentry`.
Example usage:
```js
this.$sentryReady().then((sentry) => sentry.captureMessage('Erreur!'))
// or
(await this.$sentryReady()).captureMessage('Erreur!')
```
#### `$sentryLoad`
- Type: `Function`
> Only injected when `injectLoadHook: true`.
The callback you need to call to indicate that you are ready to load Sentry.
Example usage:
```js
// layouts/default.vue
...
mounted() {
// This will only load sentry once an error was thrown
// To prevent a chicken & egg issue, make sure to also
// set injectMock: true if you use this so the error
// that triggered the load will also be captured
this.errorListener = () => {
this.$sentryLoad()
window.removeEventListener('error', errorListener)
}
window.addEventListener('error', errorListener)
},
destroyed() {
window.removeEventListener('error', this.errorListener)
}
```
## Options

@@ -96,2 +155,99 @@

### lazy
- Type: `Boolean` or `Object`
- Default: `false`
- Load Sentry lazily so it's not included in your main bundle
- If `true` then the default options will be used:
```js
{
injectMock: true,
injectLoadHook: false,
mockApiMethods: true,
chunkName: 'sentry',
webpackPrefetch: false,
webpackPreload: false
}
```
- **injectMock**
- Type: `Boolean`
- Default: `true`
- Whether a Sentry mock needs to be injected that captures any calls to `$sentry` API methods while Sentry has not yet loaded. Captured API method calls are executed once Sentry is loaded
> When `injectMock: true` this module will also add a window.onerror listener. If errors are captured before Sentry has loaded then these will be reported once Sentry has loaded using sentry.captureException
```js
// pages/index.vue
beforeMount() {
// onNuxtReady is called _after_ the Nuxt.js app is fully mounted,
// so Sentry is not yet loaded when beforeMount is called
// But when you set injectMock: true this call will be captured
// and executed after Sentry has loaded
this.$sentry.captureMessage('Hello!')
},
```
- **injectLoadHook**
- Type: `Boolean`
- Default: `false`
- By default Sentry will be lazy loaded once `window.onNuxtReady` is called. If you want to explicitly control when Sentry will be loaded you can set `injectLoadHook: true`. The module will inject a `$sentryLoad` method into the Nuxt.js context which you need to call once you are ready to load Sentry
```js
// layouts/default.vue
...
mounted() {
// Only load Sentry after initial page has fully loaded
// (this example should behave similar to using window.onNuxtReady though)
this.$nextTick(() => this.$sentryLoad())
}
```
- **mockApiMethods**
- Type: `Boolean` or `Array`
- Default `true`
- Which API methods from `@sentry/browser` should be mocked. You can use this to only mock methods you really use.
- This option is ignored when `injectMock: false`
- If `mockApiMethods: true` then all available API methods will be mocked
> If `injectMock: true` then _captureException_ will always be mocked for use with the window.onerror listener
```js
// nuxt.config.js
sentry: {
lazy: {
mockApiMethods: ['captureMessage']
}
}
// pages/index.vue
mounted() {
this.$sentry.captureMessage('This works!')
this.$sentry.captureEvent({
message: `
This will throw an error because
captureEvent doesn't exists on the mock
`
})
// To circumvent this problem you could use $sentryReady
(await this.$sentryReady()).captureEvent({
message: `
This will not throw an error because
captureEvent is only executed after
Sentry has been loaded
`
})
}
```
- **chunkName**
- Type: `String`
- Default: `'sentry'`
- The _webpackChunkName_ to use, see [Webpack Magic Comments](https://webpack.js.org/API/module-methods/#magic-comments)
- **webpackPrefetch**
- Type: `Boolean`
- Default: `false`
- Whether the Sentry chunk should be prefetched
- **webpackPreload**
- Type: `Boolean`
- Default: `false`
- Whether the Sentry chunk should be preloaded
### disabled

@@ -118,4 +274,4 @@ - Type: `Boolean`

- Default: `true`
- Whether to log calls to the mocked `$sentry` client-side object in the console
- Only applies when mocked instance is used (when `disabled = true` or `disableClientSide = true`)
- Whether to log calls to the mocked `$sentry` object in the console
- Only applies when mocked instance is used (when `disabled`, `disableClientSide` or `disableServerSide` is `true`)

@@ -212,4 +368,2 @@ ### publishRelease

Copyright (c) Diederik van den Burger <diederik@glue.group>
<!-- Badges -->

@@ -216,0 +370,0 @@ [npm-version-src]: https://img.shields.io/npm/dt/@nuxtjs/sentry.svg?style=flat-square

import VueLib from 'vue'
import * as Sentry from '@sentry/browser'
import { <%= Object.keys(options.integrations).map(integration => integration).join(', ') %> } from '@sentry/integrations'
export default function (ctx, inject) {
const opts = Object.assign({}, <%= serialize(options.config) %>, {
integrations: [
<%= Object.keys(options.integrations).map(name => {
const integration = options.integrations[name]
if (name === 'Vue') {
return `new ${name}({Vue: VueLib, ...${serialize(integration)}})`
}
return `new ${name}({${Object.keys(integration).map(option => typeof integration[option] === 'function' ?
`${option}:${serializeFunction(integration[option])}` : `${option}:${serialize(integration[option])}`).join(',')}})`
}).join(',\n ') %>
]
})
<% if (options.initialize) { %>// Initialize sentry
Sentry.init(opts)<% } %>
// Inject Sentry to the context as $sentry
inject('sentry', Sentry)
ctx.$sentry = Sentry
}
import * as Sentry from '@sentry/browser'
<% if (options.logMockCalls) { %>
function createMockFunction (key) {
return (...params) => {
// eslint-disable-next-line no-console
console.warn(`$sentry.${key}() called, but sentry plugin is disabled. Arguments:`, params)
}
}
<% } else { %>
function noop () {}
<% } %>
/** @type {import('@nuxt/types').Plugin} */
export default function (ctx, inject) {
const sentryMock = {}
for (const [key, value] of Object.entries(Sentry)) {
if (typeof value === 'function') {
sentryMock[key] = <% if (options.logMockCalls) { %> createMockFunction(key) <% } else { %> noop <% } %>
}
}
// Inject mocked sentry to the context as $sentry (this is used in case sentry is disabled)
inject('sentry', sentryMock)
ctx.$sentry = sentryMock
}
/** @type {import('@nuxt/types').Module} */
export default function (ctx, inject) {
// Inject Sentry to the context as $sentry
inject('sentry', process.sentry || {})
ctx.$sentry = process.sentry || {}
}