@zjsix/vue-monitor
Version:
A simple monitoring plugin for Vue.js applications, providing error tracking, performance monitoring and user behavior analysis
126 lines (121 loc) • 4.33 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true });
/**
* 格式化日期
* @param date Date | string | undefined,不传默认当前时间
* @param format 格式字符串,不传默认 "YYYY-MM-DD HH:mm:ss"
* @returns 格式化后的日期字符串
*/
function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
const d = (new Date());
if (isNaN(d.getTime())) {
throw new Error('Invalid date provided');
}
const pad = (n) => String(n).padStart(2, '0');
const map = {
YYYY: d.getFullYear().toString(),
MM: pad(d.getMonth() + 1),
DD: pad(d.getDate()),
HH: pad(d.getHours()),
mm: pad(d.getMinutes()),
ss: pad(d.getSeconds())
};
return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (key) => map[key]);
}
class VueMonitor {
constructor(options) {
this.breadcrumbs = [];
this.reportUrl = options.reportUrl;
this.projectName = options.projectName;
this.projectVersion = options.projectVersion;
this.maxBreadcrumbs = options.maxBreadcrumbs || 20;
}
initVue(Vue, isVue3 = false) {
const handler = (err, vm, info) => {
this.reportError({
message: err.message,
stack: err.stack,
info,
url: window.location.href,
timestamp: formatDate()
});
};
if (isVue3) {
Vue.config.errorHandler = handler;
}
else {
Vue.config.errorHandler = handler;
}
}
initGlobalError() {
window.onerror = (message, source, lineno, colno, error) => {
this.reportError({
message: (message === null || message === void 0 ? void 0 : message.toString()) || 'unknown error',
stack: error === null || error === void 0 ? void 0 : error.stack,
url: window.location.href,
timestamp: formatDate()
});
};
window.onunhandledrejection = (event) => {
var _a, _b;
this.reportError({
message: ((_a = event.reason) === null || _a === void 0 ? void 0 : _a.toString()) || 'unhandled promise rejection',
stack: (_b = event.reason) === null || _b === void 0 ? void 0 : _b.stack,
url: window.location.href,
timestamp: formatDate()
});
};
}
/** 初始化用户行为埋点 */
initBehavior() {
document.addEventListener('click', e => {
const target = e.target;
this.addBreadcrumb({
type: 'click',
target: target.tagName + (target.id ? `#${target.id}` : '') + (target.className ? `.${target.className}` : ''),
timestamp: formatDate()
});
});
document.addEventListener('input', e => {
const target = e.target;
this.addBreadcrumb({
type: 'input',
target: target.tagName + (target.id ? `#${target.id}` : '') + (target.className ? `.${target.className}` : ''),
value: target.value,
timestamp: formatDate()
});
});
}
/** 添加面包屑 */
addBreadcrumb(breadcrumb) {
this.breadcrumbs.push(breadcrumb);
if (this.breadcrumbs.length > this.maxBreadcrumbs)
this.breadcrumbs.shift();
}
/** 上报错误 */
reportError(error) {
fetch(this.reportUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ projectName: this.projectName, projectVersion: this.projectVersion, error, breadcrumbs: this.breadcrumbs }),
keepalive: true,
}).catch(err => {
console.warn('上报错误失败:', err);
});
}
}
var index = {
install(app, options) {
const monitor = new VueMonitor(options);
monitor.initGlobalError();
monitor.initBehavior();
// vue3有config vue2没有
monitor.initVue(app, !!app.config);
app.config.globalProperties.$monitor = monitor;
}
};
exports.VueMonitor = VueMonitor;
exports.default = index;
//# sourceMappingURL=vue-monitor.js.map
;