npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

web-see-monitor

v1.0.0

Published

前端监控 SDK,包含性能监控、错误监控和用户行为监控

Readme

Web Monitor SDK

一个轻量级的前端监控 SDK,用于收集网页性能指标、错误信息和用户行为数据。

特性

  • 🚀 轻量级,零依赖
  • 📊 性能监控
    • 首屏加载时间
    • FCP (First Contentful Paint)
    • LCP (Largest Contentful Paint)
    • FID (First Input Delay)
    • CLS (Cumulative Layout Shift)
  • 🐛 错误监控
    • JS 运行时错误
    • Promise 未捕获异常
    • 资源加载错误
    • HTTP 请求异常
  • 👨‍💻 用户行为跟踪
    • PV/UV 统计
    • 用户点击行为
    • 页面停留时间
    • 路由变化

安装

npm install web-monitor-sdk

核心功能

1. 性能监控

  • 页面加载性能

    • 首屏加载时间(FP)
    • 首次内容绘制(FCP)
    • 最大内容绘制(LCP)
    • 首次输入延迟(FID)
    • 累积布局偏移(CLS)
  • 资源加载性能

    • 资源加载时间统计
    • 资源加载瀑布图
    • 静态资源缓存命中率
  • 接口性能

    • API 请求耗时统计
    • 接口成功/失败率
    • 慢请求追踪

2. 错误监控

  • JS 错误

    • 运行时错误捕获
    • Promise 异常监控
    • 跨域脚本错误处理
  • 资源错误

    • 图片/脚本加载失败
    • HTTP 404/500 等状态码监控
    • 接口超时监控
  • 控制台错误

    • console.error 监控
    • 自定义错误上报

3. 用户行为分析

  • 页面访问
    • PV/UV 统计
    • 访问来源分析
    • 停留时长统计
  • 用户交互
    • 点击行为追踪
    • 滚动深度分析
    • 表单操作记录

优化措施

1. 数据上报优化

  • 批量上报

    • 采用队列缓存,批量上报减少请求次数
    • 支持配置上报阈值和时间间隔
    • 页面卸载前确保数据发送完成
  • 数据压缩

    • 采用 JSON 压缩算法
    • 大数据量采用分片上传
    • 支持 gzip 压缩

2. 性能优化

  • 采样控制

    • 支持按比例采样上报
    • 重要用户/错误数据优先上报
    • 动态调整采样率
  • 节流与防抖

    • 高频事件节流处理
    • 连续错误防抖优化
    • 避免重复上报

3. 稳定性优化

  • 容错处理

    • SDK 异常自动恢复
    • 关键流程容错
    • 上报失败重试机制
  • 浏览器兼容

    • 优雅降级处理
    • Polyfill 按需加载
    • 主流浏览器全覆盖

实现细节

1. 性能数据采集

  • 使用 Performance API 采集加载性能
  • 使用 PerformanceObserver 监听性能事件
  • 通过 requestAnimationFrame 计算渲染性能

2. 错误监控实现

  • window.onerror 捕获 JS 运行时错误
  • unhandledrejection 事件捕获 Promise 异常
  • 重写 XMLHttpRequest 和 fetch 监控接口异常

3. 行为数据收集

  • 使用事件委托优化点击监听
  • 通过 MutationObserver 监控 DOM 变化
  • 路由监听支持 hash 和 history 模式

4. 上报优化实现

  • 使用 requestIdleCallback 在空闲时段上报
  • 采用 Navigator.sendBeacon 处理页面卸载场景
  • IndexedDB 存储离线数据 // ... 前面内容保持不变 ...

优化措施及实现

1. 数据上报优化

批量上报实现

class Reporter {
  private queue: any[] = [];
  private timer: number | null = null;
  private readonly threshold = 10; // 队列阈值
  private readonly interval = 5000; // 上报间隔

  push(data: any) {
    this.queue.push(data);
    if (this.queue.length >= this.threshold) {
      this.flush();
    } else {
      this.setupTimer();
    }
  }

  private setupTimer() {
    if (!this.timer) {
      this.timer = window.setTimeout(() => this.flush(), this.interval);
    }
  }

  private flush() {
    if (this.queue.length === 0) return;
    
    // 使用 sendBeacon 保证页面卸载时数据发送
    const data = JSON.stringify(this.queue);
    navigator.sendBeacon('/collect', data);
    
    this.queue = [];
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }
}

数据压缩实现

class DataCompressor {
  compress(data: any) {
    // 1. 移除冗余字段
    const cleaned = this.removeRedundant(data);
    
    // 2. 数据编码压缩
    const compressed = this.encode(cleaned);
    
    // 3. 大数据分片处理
    return this.slice(compressed);
  }

  private encode(data: any) {
    // 短字符串映射
    const dictionary: Record<string, string> = {
      'error': 'e',
      'warning': 'w',
      'info': 'i',
      'performance': 'p'
    };
    
    return JSON.stringify(data).replace(
      /("error"|"warning"|"info"|"performance")/g,
      match => dictionary[match.replace(/"/g, '')] || match
    );
  }
}

2. 性能优化实现

采样控制实现

class SamplingController {
  private readonly defaultRate = 0.1; // 默认采样率10%
  
  shouldReport(data: any): boolean {
    // 错误数据100%采样
    if (data.type === 'error') return true;
    
    // VIP用户100%采样
    if (data.userType === 'vip') return true;
    
    // 其他数据按比例采样
    return Math.random() < this.getRate(data.type);
  }

  private getRate(type: string): number {
    const rateMap = {
      performance: 0.1,
      behavior: 0.05,
      custom: 0.01
    };
    return rateMap[type] || this.defaultRate;
  }
}

节流防抖实现

function debounce<T extends (...args: any[]) => any>(
  fn: T,
  wait: number
): (...args: Parameters<T>) => void {
  let timer: number | null = null;
  
  return function(...args: Parameters<T>) {
    if (timer) clearTimeout(timer);
    timer = window.setTimeout(() => {
      fn.apply(this, args);
      timer = null;
    }, wait);
  };
}

// 错误上报防抖
const reportError = debounce((error: Error) => {
  reporter.send({
    type: 'error',
    message: error.message,
    stack: error.stack
  });
}, 2000);

3. 稳定性优化实现

容错处理实现

class ErrorBoundary {
  private retryTimes = 3;
  
  async sendData(data: any) {
    for (let i = 0; i < this.retryTimes; i++) {
      try {
        await this.send(data);
        return;
      } catch (err) {
        if (i === this.retryTimes - 1) {
          // 存储到 IndexedDB 待后续上报
          await this.saveToIndexedDB(data);
        }
        // 指数退避重试
        await this.sleep(Math.pow(2, i) * 1000);
      }
    }
  }

  private async saveToIndexedDB(data: any) {
    const db = await this.openDB();
    const tx = db.transaction('reports', 'readwrite');
    await tx.objectStore('reports').add(data);
  }
}

浏览器兼容实现

class BrowserAdapter {
  // Performance API 兼容
  getFirstPaint() {
    if (window.performance && window.performance.getEntriesByType) {
      const [entry] = performance.getEntriesByType('paint');
      return entry ? entry.startTime : null;
    }
    // 降级方案
    return this.getFallbackTiming();
  }

  // 优雅降级
  private getFallbackTiming() {
    if (performance.timing) {
      return performance.timing.domLoading - performance.timing.navigationStart;
    }
    return Date.now(); // 最后的降级方案
  }
}

4. 离线存储实现

class OfflineStorage {
  private readonly DB_NAME = 'monitor_sdk';
  private readonly STORE_NAME = 'offline_data';
  
  async init() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.DB_NAME, 1);
      
      request.onerror = () => reject(request.error);
      request.onsuccess = () => resolve(request.result);
      
      request.onupgradeneeded = (event) => {
        const db = (event.target as IDBOpenDBRequest).result;
        db.createObjectStore(this.STORE_NAME, { 
          keyPath: 'id',
          autoIncrement: true 
        });
      };
    });
  }

  async saveOfflineData(data: any) {
    const db = await this.init();
    return new Promise((resolve, reject) => {
      const tx = (db as IDBDatabase)
        .transaction(this.STORE_NAME, 'readwrite');
      const store = tx.objectStore(this.STORE_NAME);
      
      const request = store.add({
        data,
        timestamp: Date.now()
      });
      
      request.onsuccess = () => resolve(request.result);
      request.onerror = () => reject(request.error);
    });
  }
}

使用示例

const monitor = new WebMonitor({
  appId: 'your-app-id',
  // 开启性能监控
  enablePerformance: true,
  // 开启错误监控
  enableError: true,
  // 采样率配置
  sampling: {
    performance: 0.1,
    behavior: 0.05
  },
  // 上报配置
  report: {
    threshold: 10,
    interval: 5000
  }
});

// 启动监控
monitor.start();

这些优化措施的实现代码展示了:

  1. 如何实现批量上报和数据压缩
  2. 采样控制的具体逻辑
  3. 防抖节流的实现方式
  4. 错误重试和容错处理
  5. 浏览器兼容性处理
  6. 离线数据存储的实现

通过这些实现,可以确保监控 SDK 在各种场景下都能稳定高效地运行。