Skip to content

Commit

Permalink
add debug log level
Browse files Browse the repository at this point in the history
  • Loading branch information
nruffing committed Jan 6, 2024
1 parent 9373341 commit a9bd0c8
Show file tree
Hide file tree
Showing 9 changed files with 103 additions and 22 deletions.
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,19 @@ createApp(App).use(NativeEventVue, options)

| Property | Type | Description |
| --- | --- | --- |
| `debugLog` | `boolean` or `undefined` | Print additional debugging information to the console. |
| `debugLog` | [`DebugLogLevel`](#debug-log-level) or `undefined` | Print additional debugging information to the console. By default a log level of `Error` is used. |
| `nativeEventDirectiveName` | `string` or `undefined` | Optionally specify what to register for the native-event directive. By default this is `native-event` and the directive would be `v-native-event`. |
| `propNamePrefix` | `string` or `undefined` | When an event is attached using this library a reference to the the libraries event instance is stored on the attached element using a property prefixed with this value and ending in the event name. This defaults to `native-event-vue-`. |

#### Debug Log Level

| Level | Description |
| --- | --- |
| `Error` | Only errors are logged. |
| `Info` | Additional debugging information is logged when events are attached and detached. |
| `Verbose` | All additional debugging information is logged including when directive hooks fire and is certain situations in the debouncing logic. |


## Usage

Native HTML events can be attached and debounced using either the `v-native-event` directive or the `useNativeEvent` composable depending on your situation.
Expand Down Expand Up @@ -139,6 +148,10 @@ The following debounce behavior modes are available via the `DebounceMode` enum.

## Release Notes

### v1.2.0
* Add debug logging level
* Additional source documentation

### v1.1.0
* Add `ImmediateAndTimeout` and `MaximumFrequency` debounce modes. The default mode is now called `Timeout` and acts just as the debounce did previously.

Expand Down
4 changes: 2 additions & 2 deletions e2e/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { NativeEventVue } from 'native-event-vue'
import { NativeEventVue, DebugLogLevel } from 'native-event-vue'

createApp(App).use(router).use(NativeEventVue, { debugLog: true }).mount('#app')
createApp(App).use(router).use(NativeEventVue, { debugLogLevel: DebugLogLevel.Verbose }).mount('#app')
36 changes: 34 additions & 2 deletions lib/NativeEventVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,40 @@ import type { App } from 'vue'
import { nativeEventDirective } from './directives/nativeEvent'
import { log } from './logger'

export enum DebugLogLevel {
/**
* Only errors are logged.
*/
Error = 0,
/**
* Additional debugging information is logged when events are attached and detached.
*/
Info = 1,
/**
* All additional debugging information is logged including when directive hooks fire and is certain situations in the debouncing logic.
*/
Verbose = 2,
}

export interface NativeEventVueOptions {
/**
* Print additional debugging information to the console. By default a log level of `Error` is used.
*/
debugLogLevel?: DebugLogLevel
/**
* Optionally specify what to register for the native-event directive. By default this is `native-event` and the directive would be `v-native-event`.
*/
nativeEventDirectiveName?: string
debugLog?: boolean
/**
* When an event is attached using this library a reference to the the libraries event instance is stored on the attached element using a property
* prefixed with this value and ending in the event name. This defaults to `native-event-vue-`.
*/
propNamePrefix?: string
}

export const nativeEventVueOptions = {
nativeEventDirectiveName: 'native-event',
debugLog: false,
debugLogLevel: DebugLogLevel.Error,
propNamePrefix: 'native-event-vue-',
} as NativeEventVueOptions

Expand All @@ -23,6 +48,13 @@ export default {
},
}

/**
* Resolves the property name used to store the event instance on the element
* based on the configured prefix and the event name.
* @param event The event name.
* @returns The resolved property name.
* @see {@link NativeEventVueOptions.propNamePrefix}
*/
export function resolveEventPropNamePrefix(event: string) {
return `${nativeEventVueOptions.propNamePrefix}${event}`
}
11 changes: 6 additions & 5 deletions lib/composables/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ref } from 'vue'
import { log } from '../logger'
import { useEnsure } from './useEnsure'
import { DebugLogLevel } from '../NativeEventVue'

export type FunctionToDebounce = (...args: any[]) => unknown

Expand Down Expand Up @@ -71,7 +72,7 @@ export function useDebounce(
* If this is the first call, execute immediately
*/
if (!lastCallTimestamp.value) {
log('useDebounce | first call', { args })
log('useDebounce | first call', { args }, DebugLogLevel.Verbose)
lastArgs.value = args
return execute()
}
Expand All @@ -82,7 +83,7 @@ export function useDebounce(
*/
const elapsed = Date.now() - lastCallTimestamp.value
if (!timeoutId.value && elapsed > timeoutMs) {
log('useDebounce | subsequent call within timeout', { args, elapsed })
log('useDebounce | subsequent call within timeout', { args, elapsed }, DebugLogLevel.Verbose)
lastArgs.value = args
return execute()
}
Expand All @@ -103,12 +104,12 @@ export function useDebounce(

timeoutId.value = window.setTimeout(() => {
execute()
log('useDebounce | timeout reached', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value })
log('useDebounce | timeout reached', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value }, DebugLogLevel.Verbose)
}, timeout)

log('useDebounce | timeout reset', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value, timeout })
log('useDebounce | timeout reset', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value, timeout }, DebugLogLevel.Verbose)
} else {
log('useDebounce | maximum frequency mode skip', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value })
log('useDebounce | maximum frequency mode skip', { args: lastArgs.value, lastCallTimestamp: lastCallTimestamp.value }, DebugLogLevel.Verbose)
}
}

Expand Down
12 changes: 12 additions & 0 deletions lib/composables/useNativeEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ import { resolveEventPropNamePrefix } from '../NativeEventVue'

export type NativeEvent = { destroy: () => void } | undefined

/**
* Composable to attach an HTML native event to an element.
* @param domEl The DOM element to attach the event listener to.
* @param event The name of the native event (e.g. `resize`).
* @param listener The event handler function to attach. This is the same type as the browser
* API [`addEventListener.listener` parameter](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_event_listener_callback).
* @param options Optional. This is the same type as the browser API [`addEventListener.options` parameter](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
* @param debounceMs Optionally specify a debounce timeout.
* @param debounceMode Specify the type of desired debounce behavior. Defaults to `Timeout`.
* @param replaceExisting Optionally specify to replace any existing event handler that was attached using `native-event-vue`. Otherwise the new event listener will not be attached.
* @returns {@link NativeEvent} object with a destroy method to remove the event listener.
*/
export function useNativeEvent(
domEl: HTMLElement,
event: string,
Expand Down
27 changes: 23 additions & 4 deletions lib/directives/nativeEvent.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
import type { DirectiveBinding, VNode } from 'vue'
import { log } from '../logger'
import { useNativeEvent } from '../composables/useNativeEvent'
import { resolveEventPropNamePrefix } from '../NativeEventVue'
import { DebugLogLevel, resolveEventPropNamePrefix } from '../NativeEventVue'
import type { DebounceMode } from '../composables/useDebounce'

export interface NativeEventOptions {
/**
* The name of the native event (e.g. `resize`).
*/
event: string
/**
* The event handler function to attach. This is the same type as the browser
* API [`addEventListener.listener` parameter](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#the_event_listener_callback).
*/
listener: EventListenerOrEventListenerObject
/**
* Optional. This is the same type as the browser API [`addEventListener.options` parameter](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
*/
options?: boolean | AddEventListenerOptions
/**
* Optionally specify a debounce timeout.
*/
debounceMs?: number
/**
* Specify the type of desired debounce behavior. Defaults to `Timeout`.
*/
debounceMode?: DebounceMode
/**
* Optionally disable/remove the event handler.
*/
disabled?: boolean | null | undefined
}

Expand All @@ -25,7 +44,7 @@ export const nativeEventDirective = {
}

addEventListener(domEl, binding, true)
log('native-event | beforeMount', { domEl, binding: binding.value })
log('native-event | beforeMount', { domEl, binding: binding.value }, DebugLogLevel.Verbose)
},
updated: (
domEl: HTMLElement,
Expand All @@ -37,7 +56,7 @@ export const nativeEventDirective = {
return removeEventListener(domEl, binding)
}
addEventListener(domEl, binding, false)
log('native-event | updated', { domEl, binding: binding.value })
log('native-event | updated', { domEl, binding: binding.value }, DebugLogLevel.Verbose)
},
beforeUnmount: (
domEl: HTMLElement,
Expand All @@ -46,7 +65,7 @@ export const nativeEventDirective = {
prevVnode: VNode<any, HTMLElement> | null,
) => {
removeEventListener(domEl, binding)
log('native-event | beforeUnmount', { domEl, binding: binding.value })
log('native-event | beforeUnmount', { domEl, binding: binding.value }, DebugLogLevel.Verbose)
},
}

Expand Down
15 changes: 9 additions & 6 deletions lib/logger.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import { nativeEventVueOptions } from './NativeEventVue'
import { DebugLogLevel, nativeEventVueOptions } from './NativeEventVue'

function shouldLog(): boolean {
return nativeEventVueOptions.debugLog === true || import.meta.env['VITE_DEBUG_NATIVE_EVENT_VUE'] === 'true'
function shouldLog(logLevel: DebugLogLevel): boolean {
return (nativeEventVueOptions.debugLogLevel ?? DebugLogLevel.Error) >= logLevel || import.meta.env['VITE_DEBUG_NATIVE_EVENT_VUE'] === 'true'
}

export function log(eventName: string, data: any) {
if (shouldLog()) {
export function log(eventName: string, data: any, logLevel: DebugLogLevel = DebugLogLevel.Info) {
if (logLevel === DebugLogLevel.Error) {
return logError(eventName, data)
}
if (shouldLog(logLevel)) {
console.groupCollapsed(`%c native-event-vue | ${eventName} | ${new Date().toISOString()}`, 'color: orange; font-weight: bold;')
console.log({ eventName, ...data })
console.groupEnd()
}
}

export function logError(eventName: string, data: any) {
if (shouldLog()) {
if (shouldLog(DebugLogLevel.Error)) {
console.groupCollapsed(`%c ERROR native-event-vue | ${eventName} | ${new Date().toISOString()}`, 'color: red; font-weight: bold;')
console.error({ eventName, ...data })
console.groupEnd()
Expand Down
3 changes: 2 additions & 1 deletion lib/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import NativeEventVue, { type NativeEventVueOptions, nativeEventVueOptions, resolveEventPropNamePrefix } from './NativeEventVue'
import NativeEventVue, { type NativeEventVueOptions, nativeEventVueOptions, resolveEventPropNamePrefix, DebugLogLevel } from './NativeEventVue'
import { useNativeEvent, type NativeEvent } from './composables/useNativeEvent'
import { DebounceMode } from './composables/useDebounce'
import { type NativeEventOptions } from './directives/nativeEvent'
Expand All @@ -12,4 +12,5 @@ export {
type NativeEvent,
type NativeEventOptions,
DebounceMode,
DebugLogLevel,
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "native-event-vue",
"version": "1.1.0",
"version": "1.2.0",
"type": "module",
"private": false,
"description": "Directives and composables for wiring up and debouncing native HTML events in Vue.",
Expand Down

0 comments on commit a9bd0c8

Please sign in to comment.