Feel-good tool for FP, FCP, FID performance categories and component lifecycle performance, written by Google Development team engineer Leonardo Zizzamia. Personally feel good, translated Readme and PR has been merged into the main branch.

Perfume.js

A flexible library that measures the time of first DOM generation (FP/FCP), earliest user operable time (FID), and component lifecycle performance. Report actual user measurements to Google Analytics or your preferred tracking tool.





English | simplified Chinese

Why Perfume.js?

  • ⏰ Get accurate performance information with the latest apis
  • 🔨 Cross-browser testing
  • 🚿 Filter spurious results
  • 🔭 browser tracker built in
  • 🤙 supports async/await syntax
  • 🛰 Flexible tracking tool
  • ⚡️ Built-in Idle Until Urgent policy, 0 ms waste

User-centric performance metrics

Perfume takes advantage of the latest W3C Performance proposals, such as PerformanceObserver, to test important Performance information! ⚡ ️

  • First drawing (FP)
  • First Content Rendering (FCP)
  • First input delay (FID)
  • Framework and component life cycle monitoring

The installation

NPM (www.npmjs.com/package/per)… :

npm install perfume.js --save-dev
Copy the code

The introduction of

You can import the entire library directly.

import Perfume from 'perfume.js';
Copy the code

It can also be imported directly using Universal Module Definition (UMD).

import Perfume from 'node_modules/perfume.js/dist/perfume.umd.min.js';
Copy the code

Start measuring

First drawing (FP)

FP marks the point at which the browser renders any content that is visually different from the content of the screen before navigation

const perfume = new Perfume({
  firstPaint: true
});
// Perfume.js: First Paint 1482.00 ms
Copy the code

First content drawing (FCP)

FCP marks the point at which the browser renders the first content from the DOM, which could be text, image, SVG, or even a

element.

const perfume = new Perfume({
  firstContentfulPaint: true
});
// Perfume.js: First Contentful Paint 2029.00 ms
Copy the code

First input delay (FID)

FID measures the delay between when a user first interacts with the site (that is, when they click a link, click a button, or use a custom, javascript-driven control) and when the browser is actually able to respond to that interaction.

const perfume = new Perfume({
  firstInputDelay: true
});
// Perfume.js: First Input Delay 3.20 ms
Copy the code

Mark metrics in developer tools

Performance tags (Custom time measurement API) are used to create custom performance tags in the browser’s performance entries.

perfume.start('fibonacci');
fibonacci(400);
perfume.end('fibonacci');
// Perfume.js: fibonacci 0.14 ms
Copy the code

Component first render

When the browser renders the pixel to the screen, this metric marks the point as soon as the new component is created.

perfume.start('togglePopover');
$(element).popover('toggle');
perfume.endPaint('togglePopover');
// Perfume.js: togglePopover 10.54 ms
Copy the code

Custom logging

Keep it for a while and print it out the way you want

const perfume = new Perfume({
  logPrefix: '🍹 HayesValley. Js:'
});
perfume.start('fibonacci');
fibonacci(400);
const duration = this.perfume.end('fibonacci');
perfume.log('Custom logging', duration);
// 🍹 hayesvalley.js: Custom logging 0.14ms
Copy the code

The framework

Angular

In the Angular framework, we first configure Perfume to collect initialization performance metrics (such as FCP,FID), and first make sure to introduce PefumeModule in the NgModule to make the PerformanceObserver work.

Use the @perfumeAfterViewinit () decorator in large applications to listen for the rendering performance of complex components. Avoid using it in NgFor and focus on components that contain smaller sets of components.

NgPerfume exposes methods and attributes for all Perfume instances, allowing you to tag the lifecycle of the component and monitor how long it takes to draw the component using APIs.

import { NgPerfume, PerfumeModule, PerfumeAfterViewInit } from 'perfume.js/angular';
import { AppComponent } from './app.component';
import { AppApi } from './app-api';

@Component({
  selector: 'app-root'.templateUrl: './app.component.html'.styleUrls: ['./app.component.less'],
})
@PerfumeAfterViewInit('AppComponent')
export class AppComponent implements AfterViewInit {
  data: AwesomeType;

  constructor(public perfume: NgPerfume) {
    // Start measuring the component time to draw
    this.perfume.start('AppComponentAfterPaint');
  }

  ngAfterViewInit() {
    this.loadAwesomeData();
  }

  loadAwesomeData = async() = > {await AppApi.loadAmazingData();
    this.data = AppApi.loadAwesomeData();
    // Finish measuring component drawing time
    this.perfume.endPaint('AppComponentAfterPaint'); }}// Perfume.js config, supports AOT and DI
export const PerfumeConfig = {
  firstContentfulPaint: true.firstInputDelay: true}; @NgModule({declarations: [AppComponent],
  imports: [PerfumeModule.forRoot(PerfumeConfig), BrowserModule],
  bootstrap: [AppComponent],
})
export class AppModule {}
Copy the code

React

With the React framework, we can start configuring Perfume to collect initial performance metrics (such as FCP,FID).

The perfume.start() and perfume.endpaint () apis are used for the life cycle of the component to measure the time it takes to draw the component.

import React from 'react';
import Perfume from 'perfume.js';

import { AppApi } from './AppApi';

const perfume = new Perfume({
  firstContentfulPaint: true.firstInputDelay: true
});

export default class App extends React.Component {

  constructor() {
    // Start measuring the component time to draw
    perfume.start('AppAfterPaint');
  }

  loadData = async() = > {await AppApi.loadAmazingData();
    await AppApi.loadAwesomeData();
    // Finish measuring component drawing time
    perfume.endPaint('AppAfterPaint');
  }

  render() {
    const data = this.loadData();
    return (
      <div>
        <h2>Awesome App</h2>
        <div>{data}</div>
      </div>); }}Copy the code

Analysis of the

Google Analytics

If you want to send Perfume results to Google Analytics User Timing, set enable: True and custom User timing variable timingVar:”name”.

const perfume = new Perfume({
  googleAnalytics: {
    enable: true.timingVar: 'userId'}});Copy the code

Common analysis platform support

Configure callbacks in Perfume. Js to support any platform

const perfume = new Perfume({
  analyticsTracker: (metricName, duration, browser) = >{ myAnalyticsTool.track(metricName, duration, browser.name, browser.os); })});Copy the code

Custom & toolset

The default option

Give Perfume. Js a default option in the constructor.

const options = {
  // Metrics
  firstContentfulPaint: false.firstPaint: false.firstInputDelay: false.// Analytics
  analyticsTracker: undefined.browserTracker: false.googleAnalytics: {
    enable: false.timingVar: 'name',},// Logging
  logPrefix: 'Perfume.js:'.logging: true.maxMeasureTime: 15000.warning: false.debugging: false};Copy the code

Tool set

Perfume. Js exposes a number of methods and properties that might be useful to anyone extending the library.

const perfume = new Perfume({
  firstContentfulPaint: true.firstInputDelay: true});// Values
perfume.firstPaintDuration;
perfume.firstContentfulPaintDuration;
perfume.firstInputDelayDuration;

// Aync Values
const durationFCP = await perfume.observeFirstContentfulPaint;
const durationFID = await perfume.observeFirstInputDelay;

// Send the custom user time id to Google Analytics
perfume.sendTiming(metricName, durationFCP);
Copy the code

The development of

  • npm start: Run npm run build in watch mode
  • npm run test: Run test suite
  • npm run test:watch: Run test suite in interactive watch mode
  • npm run build: Generate bundles and typings
  • npm run lint: Lints code

The article

  • First (Contentful) Paint with a touch of Perfume(.js)
  • Time to Interactive with RUM