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 🙏

© 2024 – Pkg Stats / Ryan Hefner

lcl-monitor-sdk

v1.1.1

Published

**尚在开发测试中**-"version": "1.1.1" 目标:可以采集和上报错误信息和性能指标(包括但不限于FCP、LCP),兼容至Chrome39+

Downloads

18

Readme

lcl-monitor-sdk

尚在开发测试中-"version": "1.1.1" 目标:可以采集和上报错误信息和性能指标(包括但不限于FCP、LCP),兼容至Chrome39+

这是一个前端异常和性能监控的采集上报SDK

异常监控:JS运行时异常;资源异常;未捕获的promise异常;xhr/fetch错误;白屏

性能监控:web-vitals三个核心指标和三个辅助指标;页面加载时间相关指标:tcp连接耗时、dom解析耗时、首次可交互时间等;卡顿;输入延时

使用方法

  • 基本用法
// npm引入方式
npm i lcl-monitor-sdk

import Monitor from 'lcl-monitor-sdk'

const monitor = new Monitor({
    requestUrl: "http://localhost:8080/monitor/",  // 上报接口地址,必填
    jsError: true,  // JS异常会上报到http://localhost:8080/monitor/JsError,webVitals会上报到http://localhost:8080/monitor/webVitals
    webVitals: true
})

// script引入方式
<script src="dist/index.js"></script>
<script type="text/javascript">
const monitor = new Monitor({
    requestUrl: "http://localhost:8080/monitor/", 
    jsError: true,
    webVitals: true
})
</script>
  • options 介绍
/**
 * @uuid 用户id,保留字段,用户行为统计中可能会用到
 * @requestUrl 上报接口地址
 * @reportTiming 数据上报时间点,默认为采集到数据即上报。目前仅可选'beforeunload',在页面卸载前统一上报
 * @isLog 开启后采集的数据在控制台打印,不上报
 * @jsError 是否开启js运行时异常、资源加载异常、未捕获的promise异常上报
 * @xhrAndFetch 是否开启xhr和fetch请求异常的上报
 * @blankScreen 是否开启白屏情况的上报
 * @blankScreenDuration 传入毫秒数自定义白屏认定的阈值
 * @loadTiming 是否开启tcp连接耗时、ttfb、dom解析耗时、首次可交互时间等页面加载时间的上报
 * @webVitals 是否开启谷歌的web-vitals性能监测指标上报,包括CLS、FID、FCP、LCP、TTFB、INP
 * @longTask 是否开启卡顿上报
 * @inputDelay 是否开启输入延时上报
 */
DefaultOptions:{
    uuid: string | undefined
    requestUrl: string | undefined
    reportTiming: string | 'auto'
    isLog: boolean | false
    jsError: boolean | false
    xhrAndFetch: boolean | false
    blankScreen: boolean | false
    blankScreenDuration: number | 3000
    loadTiming: boolean | false
    webVitals: boolean | false
    longTask: boolean | false
    inputDelay: boolean | false
}
  • 手动上报
const monitor = new Monitor({
    requestUrl: "http://localhost:8080/monitor/", 
    jsError: true
})

// 手动上报
/**
 * @data 请求体,对象格式
 * @type 自定义上报类型(即接口的二级地址,http://localhost:8080/monitor/type)
 */
monitor.manualReporting(data, type)

数据采集

异常采集

  • jsError-JS异常

    通过window.addEventListener('error')捕获JS运行时异常和资源加载异常,window.addEventListener('unhandledrejection')捕获未处理的promise reject异常

    window.addEventListener('error')能同时捕获JS运行时异常和资源加载异常,可以通过event.target && (event.target.src || event.target.href)来区分,为true说明是资源加载异常

    window.addEventListener('error', () => {
         if (event.target && (event.target.src || event.target.href)) {
             // 资源加载异常上报
         } else {
             // JS运行时异常上报
         }
    })
    window.addEventListener('unhandledrejection', () => {
    	// 未处理的promise reject异常上报
    })
  • xhrAndFetch-接口异常

    通过重写XMLHttpRequestfetch的原生方法来实现

    重写XMLHttpRequest

    if(!window.XMLHttpRequest) return
    let XMLHttpRequest = window.XMLHttpRequest
    let oldOpen = XMLHttpRequest.prototype.open
    XMLHttpRequest.prototype.open = function (method, url) {
        this.logData = {method, url}
        return oldOpen.apply(this, arguments)
    }
    let oldSend = XMLHttpRequest.prototype.send
    XMLHttpRequest.prototype.send = function (body) {
    	if (this.status > 0 && this.status < 400) return
        let handler = (type) => (event) => {
            // 上报xhr异常
        }
        this.addEventListener('load', handler('load'), false)
        this.addEventListener('error', handler('error'), false)
        this.addEventListener('abort', handler('abort'), false)
    }
    oldSend.apply(this, arguments)

    重写fetch

    if(!window.fetch) return
    let oldFetch = window.fetch
    window.fetch = function (requestInfo, requestInit) {
        return oldFetch.apply(this, arguments)
        .then(res => {
            if (res.status >= 400) { 
                // 上报fetch异常
            }
            return res
        })
        .catch(error => {
            // 上报fetch异常
            throw error
        })
    }
  • blankScreen-白屏

    | 方案 | 实现 | 优点 | 缺点 | | :------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------- | | 基于DOM的检测 | 页面load完成后在页面中拿数个document.elementsFromPoint,拿数组的第一个即最内层元素,判断其是否为html、body、container等容器元素,是的话判定为空白点 | 相对灵活,可传入要判定为空白容器的CSS选择器、自定义elementsFromPoint数量、设置空白点上报阈值等 | elementsFromPoint数量多的情况对页面性能有一定影响,兼容性较差 | | 基于Performance API | 页面load完成后数秒内没有FP | 对页面性能几乎没有影响 | 有FP的情况下也可能是白屏 | | 基于MutationObserver | 页面load完成后数秒内有无DOM节点变化 | 对页面性能几乎没有影响 | DOM节点无变化不一定代表白屏 |

    选择通过performance.getEntriesByName('first-paint')获取FP,如果页面加载完成三秒内没有FP,则认为出现白屏异常

    onload(function () {
        setTimeout(() => {
            const FP = performance.getEntriesByName('first-paint')[0]
            if (!FP) {
    			// 上报白屏异常
            }
        }, 3000)
    })

性能采集

  • loadTiming-页面加载时间相关指标

    最新标准应该使用performancePaintTiming API,但是为了兼容Chrome39+选择通过performance.timing API实现

    包括几个相对重要的页面加载时间相关指标:TCP连接耗时(connectEnd - connectStart)、网络请求耗时即TTFB(responseStart - requestStart)、Response响应耗时(responseEnd - responseStart)、DOM解析渲染耗时(loadEventStart - domLoading)、DOMContentLoaded事件回调耗时(domContentLoadedEventEnd - domContentLoadedEventStart)、首次可交互时间即TTI(domInteractive - fetchStart)、页面完全加载时间(loadEventStart - fetchStart)、onload事件回调耗时(loadEventEnd - loadEventStart)

    onload(function () {
        setTimeout(() => {  // onload三秒后再拿性能评价指标
            const {
                fetchStart,
                connectStart,
                connectEnd,
                requestStart,
                responseStart,
                responseEnd,
                domLoading,
                domInteractive,
                domContentLoadedEventStart,
                domContentLoadedEventEnd,
                domComplete,
                loadEventStart,
                loadEventEnd
            } = performance.timing
    		// 上报页面加载时间相关指标
        }, 3000);
    });
  • webVitals-谷歌性能指标

    包括CLS、FID、FCP、LCP、TTFB、INP六个指标,前三个即Core Web Vitals

    调用Chrome的web-vitals轮子

    const reportWebVitals = onPerfEntry => {
        if (onPerfEntry && onPerfEntry instanceof Function) {
            import('web-vitals').then(({onCLS, onFID, onFCP, onLCP, onTTFB, onINP}) => {
                onCLS(onPerfEntry)
                onFID(onPerfEntry)
                onFCP(onPerfEntry)
                onLCP(onPerfEntry)
                onTTFB(onPerfEntry)
                onINP(onPerfEntry)
            });
        }
    };
      
    reportWebVitals((metric) => {
        // 上报webVitals指标
    })
  • longTask-卡顿**(无法兼容至Chrome39+)**

    响应用户交互的响应时间如果大于100ms,用户就会感觉卡顿。浏览器的事件队列机制决定,要实现小于100毫秒的响应,应用必须在每50毫秒内将控制返回给主线程,页面整个生命周期中,主线程持续执行某一个任务的耗时大于50ms就会造成卡顿

    通过PerformanceLongTask检测卡顿,可以检测到浏览器内核主线程持续执行某一个任务超过50ms的情况:

    if (typeof PerformanceObserver !=='undefined') {
    	new PerformanceObserver((list) => {
    		list.getEntries().forEach(entry => {
                if (entry.duration > 50) {
                    // 拿到最近一次触发的输入事件
                    let lastEvent = getLastEvent()
                    // requestAnimationFrame回调函数会在绘制之前执行;requestIdleCallback是在绘制之后执行,在浏览器一帧的剩余空闲时间内执行
                    requestIdleCallback(() => {
                        // 上报卡顿情况
                    });
                }
            });
        }).observe({type: "longtask", buffered: true})
    } else {
    	console.log('当前浏览器不支持longTask')
    }
  • inputDelay-输入延时**(无法兼容至Chrome39+)**

    这里主要处理事件的响应速度:从用户操作触发事件到页面响应的耗时,通常要求小于100ms

    基于PerformanceEvent监听用户的输入(如click、touchstart、mousedown、keydown、mouseover等)到浏览器给出响应的延迟时间

    if (typeof PerformanceObserver !=='undefined') {
     	new PerformanceObserver((list) => {
            // 拿到最近一次触发的输入事件
        	let lastEvent = getLastEvent()
            let event = list.getEntries()[list.getEntries().length - 1]
            if (event.duration > 100) {
    			// 上报输入延时超过100ms的慢响应情况
            }
    	}).observe({type: "event", buffered: true})
    } else {
    	console.log('当前浏览器不支持inputDelay')
    }

数据上报

  • 上报时机

    常见上报时机有页面加载时、页面卸载或页面刷新时、SPA 路由切换时、页面多个 tab 切换时

    本项目目前仅支持页面加载时(默认)和页面卸载或页面刷新时(reportTiming: 'beforeunload'

  • 上报方式

    默认使用navigator.sendBeacon进行上报,如果浏览器不兼容则使用fetch进行上报(均为post请求)

    • navigator.sendBeacon

      只能发post请求,在页面卸载后不会取消请求,可以保证数据有效送达,不会阻塞页面的卸载或加载,恰好兼容到Chrome39+,且使用简单,支持跨域。但是不支持请求数据类型:Content-Type:application/json,只支持application/x-www-form-urlencodedmultipart/form-datatext/plain三种,本项目中使用multipart/form-data数据类型

      // sendBeacon会自动设置content-type为formData格式
      const formData = new FormData()
      Object.keys(logs).forEach((key) => {
          let value = logs[key]
          if (typeof value !== 'string') {
              // formData只能append string 或 Blob
              value = JSON.stringify(value)
          }
          formData.append(key, value)
      });
      navigator.sendBeacon(url, formData)
    • fetch

      通过设置keepalive: true也可以达到类似navigator.sendBeacon在页面卸载后不会取消请求的效果。但是很可惜,fetch兼容到Chome42+,只能作为备选上报方式

      fetch(url, {
          body,
          method: 'POST',
          keepalive: true,
          headers: {'Content-Type': "application/json"}
      }).then()