UNPKG

hc-web-log-mon

Version:

基于 JS 跨平台插件,为前端项目提供【 行为、性能、异常、请求、资源、路由、曝光、录屏 】监控手段

270 lines (263 loc) 7.3 kB
import type { VoidFun } from '../types' import { _global } from '../utils/global' import { on, replaceAop, throttle, isValidKey, getTimestamp } from '../utils' import { EVENTTYPES } from '../common' import { eventBus } from './eventBus' /** * 根据入参初始化 重写、监听 * * 定义一个产出模块 * 其注册所有模块所需要的 - 监听,改写 * 当那些模块要用的时候,去产出模块那数据,这个模块的数据不应该有业务数据 * 只负责去采集数据,具体怎么拿是业务模块需要去分辨的,采集哪些数据是注册的时候决定的 * 只会管兼容性问题,不兼容的api就不做动作 * 这样就不需要所有的模块都要init了,之后需要init的模块,可以专门去做模块内的事 * 注意这里面耦合性不能太高,不要抽了还不如不抽,做到模块内改了代码不需要去另外个文件再改 */ export function initReplace(): void { for (const key in EVENTTYPES) { if (isValidKey(key, EVENTTYPES)) { replace(key) } } } function replace(type: EVENTTYPES): void { if (!isValidKey(type, EVENTTYPES)) return const value = EVENTTYPES[type] // debug('replace-初始化挂载事件:', value) switch (value) { case EVENTTYPES.ERROR: listenError(EVENTTYPES.ERROR) break case EVENTTYPES.UNHANDLEDREJECTION: listenUnhandledrejection(EVENTTYPES.UNHANDLEDREJECTION) break case EVENTTYPES.CONSOLEERROR: replaceConsoleError(EVENTTYPES.CONSOLEERROR) break case EVENTTYPES.CLICK: listenClick(EVENTTYPES.CLICK) break case EVENTTYPES.LOAD: listenLoad(EVENTTYPES.LOAD) break case EVENTTYPES.BEFOREUNLOAD: listenBeforeunload(EVENTTYPES.BEFOREUNLOAD) break case EVENTTYPES.XHROPEN: replaceXHROpen(EVENTTYPES.XHROPEN) break case EVENTTYPES.XHRSEND: replaceXHRSend(EVENTTYPES.XHRSEND) break case EVENTTYPES.FETCH: replaceFetch(EVENTTYPES.FETCH) break case EVENTTYPES.HASHCHANGE: listenHashchange(EVENTTYPES.HASHCHANGE) break case EVENTTYPES.HISTORYPUSHSTATE: replaceHistoryPushState(EVENTTYPES.HISTORYPUSHSTATE) break case EVENTTYPES.HISTORYREPLACESTATE: replaceHistoryReplaceState(EVENTTYPES.HISTORYREPLACESTATE) break case EVENTTYPES.POPSTATE: listenPopState(EVENTTYPES.POPSTATE) break case EVENTTYPES.OFFLINE: listenOffline(EVENTTYPES.OFFLINE) break case EVENTTYPES.ONLINE: listenOnline(EVENTTYPES.ONLINE) break default: break } } /** * 监听 - error */ function listenError(type: EVENTTYPES): void { on( _global, 'error', function (e: ErrorEvent) { eventBus.runEvent(type, e) }, true ) } /** * 监听 - unhandledrejection(promise异常) */ function listenUnhandledrejection(type: EVENTTYPES): void { on(_global, 'unhandledrejection', function (ev: PromiseRejectionEvent) { // ev.preventDefault() 阻止默认行为后,控制台就不会再报红色错误 eventBus.runEvent(type, ev) }) } /** * 重写 - console.error */ function replaceConsoleError(type: EVENTTYPES): void { replaceAop(console, 'error', (originalError: VoidFun) => { return function (this: any, ...args: any[]): void { if ( !(args[0] && args[0].slice && args[0].slice(0, 12) === 'hc-web-log') ) { eventBus.runEvent(type, args) } originalError.apply(this, args) } }) } /** * 监听 - click */ function listenClick(type: EVENTTYPES): void { if (!('document' in _global)) return const clickThrottle = throttle(eventBus.runEvent, 100, true) on( _global.document, 'click', function (this: any, e: MouseEvent) { clickThrottle.call(eventBus, type, e) }, true ) } /** * 监听 - load */ function listenLoad(type: EVENTTYPES): void { on( _global, 'load', function (e: Event) { eventBus.runEvent(type, e) }, true ) } /** * 监听 - beforeunload */ function listenBeforeunload(type: EVENTTYPES): void { on( _global, 'beforeunload', function (e: BeforeUnloadEvent) { eventBus.runEvent(type, e) }, false ) } /** * 重写 - XHR-open */ function replaceXHROpen(type: EVENTTYPES): void { if (!('XMLHttpRequest' in _global)) return replaceAop(XMLHttpRequest.prototype, 'open', (originalOpen: VoidFun) => { return function (this: any, ...args: any[]): void { eventBus.runEvent(type, ...args) originalOpen.apply(this, args) } }) } /** * 重写 - XHR-send */ function replaceXHRSend(type: EVENTTYPES): void { if (!('XMLHttpRequest' in _global)) return replaceAop(XMLHttpRequest.prototype, 'send', (originalSend: VoidFun) => { return function (this: any, ...args: any[]): void { eventBus.runEvent(type, this, ...args) originalSend.apply(this, args) } }) } /** * 重写 - fetch */ function replaceFetch(type: EVENTTYPES): void { if (!('fetch' in _global)) return replaceAop(_global, 'fetch', originalFetch => { return function (this: any, ...args: any[]): void { const fetchStart = getTimestamp() return originalFetch.apply(_global, args).then((res: any) => { eventBus.runEvent(type, ...args, res, fetchStart) return res }) } }) } /** * 监听 - hashchange */ function listenHashchange(type: EVENTTYPES): void { // 通过onpopstate事件,来监听hash模式下路由的变化 on(_global, 'hashchange', function (e: HashChangeEvent) { eventBus.runEvent(type, e) }) } /** * 重写 - history-replaceState */ function replaceHistoryReplaceState(type: EVENTTYPES): void { if (!('history' in _global)) return if (!('pushState' in _global.history)) return replaceAop(_global.history, 'replaceState', (originalSend: VoidFun) => { return function (this: any, ...args: any[]): void { eventBus.runEvent(type, ...args) originalSend.apply(this, args) } }) } /** * 重写 - history-pushState */ function replaceHistoryPushState(type: EVENTTYPES): void { if (!('history' in _global)) return if (!('pushState' in _global.history)) return replaceAop(_global.history, 'pushState', (originalSend: VoidFun) => { return function (this: any, ...args: any[]): void { eventBus.runEvent(type, ...args) originalSend.apply(this, args) } }) } /** * 监听 - popstate */ function listenPopState(type: EVENTTYPES): void { on(_global, 'popstate', function (e: HashChangeEvent) { eventBus.runEvent(type, e) }) } /** * 监听 - offline 网络是否关闭 */ function listenOffline(type: EVENTTYPES): void { on( _global, 'offline', function (e: ErrorEvent) { eventBus.runEvent(type, e) }, true ) } /** * 监听 - online 网络是否开启 */ function listenOnline(type: EVENTTYPES): void { on( _global, 'online', function (e: ErrorEvent) { eventBus.runEvent(type, e) }, true ) }