Skip to content

Commit

Permalink
refactor(options): refactor options resolving (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
rchl authored Feb 25, 2022
1 parent 6152957 commit 9922247
Show file tree
Hide file tree
Showing 8 changed files with 249 additions and 177 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ module.exports = {
extends: [
'@nuxtjs/eslint-config'
],
ignorePatterns: ['dist/'],
rules: {
'import/named': 'off',
'import/namespace': 'off',
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ jobs:
CI: true
strategy:
matrix:
node-version: [12.x, 14.x]
node-version: [12.x, 14.x, 16.x]
name: Use Node.js ${{ matrix.node-version }}
steps:
- uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: yarn
- name: yarn install
run: yarn
- name: Unittesting
run: yarn test
- name: Linting
if: ${{ matrix.node-version == '16.x' }}
run: yarn lint
- name: Coverage
run: yarn coverage
195 changes: 26 additions & 169 deletions lib/core/hooks.js
Original file line number Diff line number Diff line change
@@ -1,175 +1,46 @@
import { resolve, posix } from 'path'
import merge from 'lodash.mergewith'
import * as Integrations from '@sentry/integrations'
import * as Sentry from '@sentry/node'
import { canInitialize, clientSentryEnabled, envToBool, serverSentryEnabled } from './utils'
import { resolveRelease, resolveClientOptions, resolveServerOptions } from './options'

const SERVER_CONFIG_FILENAME = 'sentry.server.config.js'
const SENTRY_PLUGGABLE_INTEGRATIONS = ['CaptureConsole', 'Debug', 'Dedupe', 'ExtraErrorData', 'ReportingObserver', 'RewriteFrames', 'Vue']
const SENTRY_BROWSER_INTEGRATIONS = ['InboundFilters', 'FunctionToString', 'TryCatch', 'Breadcrumbs', 'GlobalHandlers', 'LinkedErrors', 'UserAgent']
const SENTRY_SERVER_INTEGRATIONS = ['CaptureConsole', 'Debug', 'Dedupe', 'ExtraErrorData', 'RewriteFrames', 'Modules', 'Transaction']

/** @param {import('../../types/sentry').IntegrationsConfiguration} integrations */
const filterDisabledIntegration = integrations => Object.keys(integrations).filter(key => integrations[key])

async function getBrowserApiMethods () {
const SentryBrowser = await import('@sentry/browser')

const browserMethods = []
for (const key in SentryBrowser) {
// @ts-ignore
if (typeof SentryBrowser[key] === 'function') {
browserMethods.push(key)
}
}

return browserMethods
}
const RESOLVED_RELEASE_FILENAME = 'sentry.release.config.js'

/**
* Handler for the 'build:before' hook.
*
* @param {any} moduleContainer The module container
* @param {import('../../types/sentry').ResolvedModuleConfiguration} options The module options
* @param {import('../../types/sentry').ResolvedModuleConfiguration} moduleOptions The module options
* @param {import('consola').Consola} logger The logger
* @return {Promise<void>}
*/
export async function buildHook (moduleContainer, options, logger) {
if (!('release' in options.config)) {
// Determine "config.release" automatically from local repo if not provided.
try {
// @ts-ignore
const SentryCli = await (import('@sentry/cli').then(m => m.default || m))
const cli = new SentryCli()
options.config.release = (await cli.releases.proposeVersion()).trim()
} catch {
// Ignore
}
}

options.serverConfig = merge({}, options.config, options.serverConfig)
options.clientConfig = merge({}, options.config, options.clientConfig)

const apiMethods = await getBrowserApiMethods()

// Set "lazy" defaults.
if (options.lazy) {
const defaultLazyOptions = {
injectMock: true,
injectLoadHook: false,
mockApiMethods: true,
chunkName: 'sentry',
webpackPrefetch: false,
webpackPreload: false
}

options.lazy = /** @type {Required<import('../../types/sentry').LazyConfiguration>} */(
merge({}, 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)
}
export async function buildHook (moduleContainer, moduleOptions, logger) {
const release = await resolveRelease(moduleOptions)

if (!options.lazy.mockApiMethods.includes('captureException')) {
// always add captureException if a sentry mock is requested
options.lazy.mockApiMethods.push('captureException')
}
}
}
if (options.tracing) {
options.tracing = merge({
tracesSampleRate: 1.0,
vueOptions: {
tracing: true,
tracingOptions: {
hooks: ['mount', 'update'],
timeout: 2000,
trackComponents: true
}
},
browserOptions: {}
}, typeof options.tracing === 'boolean' ? {} : options.tracing)
options.clientConfig.tracesSampleRate = options.tracing.tracesSampleRate
}

for (const name of Object.keys(options.clientIntegrations)) {
if (!SENTRY_PLUGGABLE_INTEGRATIONS.includes(name) && !SENTRY_BROWSER_INTEGRATIONS.includes(name)) {
logger.warn(`Sentry clientIntegration "${name}" is not recognized and will be ignored.`)
delete options.clientIntegrations[name]
}
}

for (const name of Object.keys(options.serverIntegrations)) {
if (!SENTRY_SERVER_INTEGRATIONS.includes(name)) {
logger.warn(`Sentry serverIntegration "${name}" is not recognized and will be ignored.`)
delete options.serverIntegrations[name]
}
}

// Register the client plugin
const pluginOptionClient = clientSentryEnabled(options) ? (options.lazy ? 'lazy' : 'client') : 'mocked'
const pluginOptionClient = clientSentryEnabled(moduleOptions) ? (moduleOptions.lazy ? 'lazy' : 'client') : 'mocked'
const clientOptions = merge({ config: { release } }, await resolveClientOptions(moduleContainer, moduleOptions, logger))
moduleContainer.addPlugin({
src: resolve(__dirname, '..', `plugin.${pluginOptionClient}.js`),
fileName: 'sentry.client.js',
mode: 'client',
options: {
SENTRY_PLUGGABLE_INTEGRATIONS,
SENTRY_BROWSER_INTEGRATIONS,
dev: moduleContainer.options.dev,
runtimeConfigKey: options.runtimeConfigKey,
config: {
dsn: options.dsn,
...options.clientConfig
},
lazy: options.lazy,
apiMethods,
logMockCalls: options.logMockCalls, // for mocked only
tracing: options.tracing,
initialize: canInitialize(options),
integrations: filterDisabledIntegration(options.clientIntegrations)
.reduce((res, key) => {
// @ts-ignore
res[key] = options.clientIntegrations[key]
return res
}, {})
}
options: clientOptions
})

// Register the server plugin
const pluginOptionServer = serverSentryEnabled(options) ? 'server' : 'mocked'
const pluginOptionServer = serverSentryEnabled(moduleOptions) ? 'server' : 'mocked'
const serverOptions = merge({ config: { release } }, await resolveServerOptions(moduleContainer, moduleOptions, logger))
moduleContainer.addPlugin({
src: resolve(__dirname, '..', `plugin.${pluginOptionServer}.js`),
fileName: 'sentry.server.js',
mode: 'server',
options: {
dev: moduleContainer.options.dev,
runtimeConfigKey: options.runtimeConfigKey,
lazy: options.lazy,
apiMethods,
logMockCalls: options.logMockCalls // for mocked only
}
options: serverOptions
})

if (serverSentryEnabled(options)) {
if (serverSentryEnabled(moduleOptions)) {
moduleContainer.addTemplate({
src: resolve(__dirname, '..', 'templates', 'options.ejs'),
fileName: SERVER_CONFIG_FILENAME,
options: {
config: options.serverConfig
}
fileName: RESOLVED_RELEASE_FILENAME,
options: { release }
})

await initializeServerSentry(moduleContainer, options)
}
}

Expand Down Expand Up @@ -216,9 +87,7 @@ export async function webpackConfigHook (moduleContainer, webpackConfigs, option
publishRelease.include.push(`${buildDir}/dist/client`)
}

if (options.config.release && !publishRelease.release) {
publishRelease.release = options.config.release
}
publishRelease.release = options.config.release || publishRelease.release || await resolveRelease(options)

if (!publishRelease.release) {
// We've already tried to determine "release" manually using Sentry CLI so to avoid webpack
Expand Down Expand Up @@ -261,41 +130,29 @@ export async function webpackConfigHook (moduleContainer, webpackConfigs, option
/**
* Initializes the sentry.
*
* @param {any} moduleContainer The module container
* @param {import('../../types/sentry').ResolvedModuleConfiguration} options The module options
* @param {any} moduleContainer
* @param {import('../../types/sentry').ResolvedModuleConfiguration} moduleOptions
* @param {import('consola').Consola} logger
* @return {Promise<void>}
*/
export async function initializeServerSentry (moduleContainer, options) {
export async function initializeServerSentry (moduleContainer, moduleOptions, logger) {
if (process.sentry) {
return
}

// Initializes server-side Sentry directly from the module.
let release
try {
const optionsPath = resolve(moduleContainer.options.buildDir, SERVER_CONFIG_FILENAME)
const { config } = await import(optionsPath)
options.serverConfig = config
const path = resolve(moduleContainer.options.buildDir, RESOLVED_RELEASE_FILENAME)
release = (await import(path)).release
} catch {
// Ignored
}

const { publicRuntimeConfig } = moduleContainer.options
const { runtimeConfigKey } = options
if (publicRuntimeConfig && runtimeConfigKey && publicRuntimeConfig[runtimeConfigKey]) {
merge(options.serverConfig, publicRuntimeConfig[runtimeConfigKey].config, publicRuntimeConfig[runtimeConfigKey].serverConfig)
}
const serverOptions = await resolveServerOptions(moduleContainer, moduleOptions, logger)
const config = merge({ release }, serverOptions.config)

if (canInitialize(options)) {
Sentry.init({
dsn: options.dsn,
...options.serverConfig,
integrations: filterDisabledIntegration(options.serverIntegrations)
.map((name) => {
const opt = options.serverIntegrations[name]
// @ts-ignore
return Object.keys(opt).length ? new Integrations[name](opt) : new Integrations[name]()
})
})
if (canInitialize(moduleOptions)) {
Sentry.init(config)
}

process.sentry = Sentry
Expand Down
Loading

0 comments on commit 9922247

Please sign in to comment.