7.0.2 • Published 6 years ago

browser-metrics-dist v7.0.2

Weekly downloads
17,207
License
-
Repository
-
Last release
6 years ago

Atlassian browser-metrics

browser-metrics vs browser-metrics-plugin

This project is a bare-bones JavaScript library, but if you're working on a product (e.g. JIRA / Confluence / Bitbucket / Bamboo), you're going to want to use browser-metrics-plugin which bundles this library inside an Atlassian Plugin, and provides some better integration with the Atlassian Platform.

Installation

Bower

Add the following to your bower.json:

"dependencies": {
    "browser-metrics": "ssh://git@bitbucket.org/atlassian/browser-metrics.git#v4.0.0"
}

There are two files that need to be executed in the browser:

  • dist/probe.js (must be loaded synchronously)
  • dist/collector.js (may be loaded asynchronously)

Assuming you serve these files from /static/, you'd add the following HTML to your page:

<script type="text/javascript" src="/static/probe.js"></script>
<script type="text/javascript" src="/static/collector.js" async></script>

Usage

browser-metrics allows subscribers to receive beacons that report on transitions that have been instrumented in the application:

var metrics = window["browser-metrics"];

metrics.start({
    key: "jira.issue.view",
    isInitial: true,
    threshold: 1000
});

// some time later…
metrics.end({key: "jira.issue.view"});

// some where else
metrics.subscribe(function (beacon) {
    console.log(beacon);  // {report: {readyForUser: …, …}}
});

A note for IE support

If you need to support Internet Explorer, make sure your page contains:

<meta http-equiv="X-UA-Compatible" content="IE=edge;" />

API

The fundamental idea in browser-metrics is to measure the duration of a transition where the application is changing from one state to another. A "transition" is a general term that may refer to:

  • Navigating from one page to another.
  • Opening a dropdown menu.
  • Submitting a form.

browser-metrics is designed to be able to measure classic "full page" navigating, in addition to modern "single page app" aka JavaScript transitions.

The API requires developers to explicitly declare the start and end of a transition.

.start().end()

The typical use of the browser-metrics API is to call .start() when the transition begins, and later call .end() after the transition has completed.

var metrics = window["browser-metrics"];
metrics.start({
    key: "jira.issue.split-view",
    isInitial: …,
    threshold: 1000
});

// Some time later...
metrics.end({key: "jira.issue.split-view"});

Calls to .end() with a key that does not correspond to the most recent call to .start() are ignored.

.start() options

The following options can be

  • key (string, required)

    A dotted-path style string that's used as the atlassian-analytics event name.

    The string must match the following syntax:

      <product>.<page>

    e.g. jira.view-issue. Don't put any . in <product>, or the post-processing we do will not work (we split on the first .).

  • isInitial (boolean, optional)

    If specified, indicates whether the transition is a "full page load". If not specified, this will be determined automatically based on whether or not DOMContentLoaded has fired.

    browser-metrics takes special care to record the browser's navigation timing in its report, however it only does this for full page loads. To avoid needing to specify isInitial, a convenience feature is supported which will implicitly cause isInitial: true if .start() is called before or during the DOMContentLoaded event. e.g.

      // before DOMContentLoaded
      var metrics = window["browser-metrics"];
      if (document.readyState !== "complete") {
          metrics.start({key: "jira.issue-view"}); // isInitial=true
      }
    
      // or during DOMContentLoaded
      document.addEventListener("DOMContentLoaded", function() {
          metrics.start({key: "jira.issue-view"}); // isInitial=true
      });
      
      // but not after DOMContentLoaded
      document.addEventListener("DOMContentLoaded", function() {
          setTimeout(function () {
              metrics.start({key: "jira.issue-view"}); // isInitial=false
          }, 0);
      });

    Be careful when using jQuery.ready(), as it executes the callback immediately if DOMContentLoaded has already fired. This means you may unintentionally get isInitial: false when you expected isInitial: true.

    In practice it's probably better to explicitly specify isInitial to reduce ambiguity.

  • threshold (integer, optional, default: 1000)

    Declares the target (in milliseconds) duration for the transition. The performance of the transition is considered good if it completes within this threshold.

    This option allows for apdex to be calculated on the transition.

    Note: The default value 1000 is used for backwards compatibility with code that written before this option was introduced. Prior to this option's existence, "page loads" were the only type of transitions being measured, and the threshold for those was 1 seconds.

  • ready (any, optional, use with caution)

    Note: This is only supported on browsers where MutationObserver and Promise are available. On unsupported browsers this option is ignored, and measurements are not made.

    A description of DOM elements that must exist in the DOM for the page to be considered "done". Using this option avoids needing to manually call .end(). This is supposed to be a "friendly" API that is easy to adopt to existing codebases where "the page is loaded" JavaScript hooks don't exist.

    If you care only about a single element, pass a single CSS selector.

    If multiple elements need to be present, pass an array of selectors. After all selectors have matched, the page is considered loaded:

      metrics.start({
          key: "jira.issue.split-view",
          ready: [
              ".content-thing",
              "#another-thing > .something"
          ]
      });

    Performance needs to be considered here -- as you add more selectors, more overhead is added to DOM mutation. To improve performance, keep the number of selectors to a minimum, and keep each selector simple (avoid child/descendant selectors).

    The semantics of when an element is "present" fall into two scenarios:

    1. If the selector immediately matches one or more elements in the DOM, that selector is considered to be satisfied.
    2. If the selector doesn't immediately match any elements in the DOM, as soon as an element in the DOM matches the selector it is considered satisfied. This can either happen by it being inserted directly or as part of a subtree, or being exposed via an attribute change to an ancestor.

      If you are interested in some task which is in progress currently and will be resolved at some point in time, you can use "hasNone" condition along with selector. The idea is to insert an element with certain CSS selector inside parent container so it will be a flag of that work for this container is still in progress (i.e. content not fully loaded):

      metrics.start({
          key: "jira.issue.split-view",
          ready: [
              {
                  selector: ".parent-content-thing",
                  hasNone: ".loading" // <-- presence of this element inside "selector" indicates work is in progress
              },
              "#another-thing > .something"
          ]
      });

      It means that in order to submit event timings we have to wait until there won't be any elements inside parent container (which is discovered using "selector") matching "hasNone".


      By default the ready options only makes guarantees about DOM state (as opposed to the CSSOM and render tree). This means that there's no guarantee that the DOM has actually been painted, and under certain scenarios can give wildly inaccurate readyForUser values.

      A requirePaint option is available for ready to require a paint, which avoids this problem:

      metrics.start({
          key: "jira.issue.split-view",
          ready: {
              rules: [
                  {
                      selector: ".parent-content-thing",
                      hasNone: ".loading" // <-- presence of this element inside "selector" indicates work is in progress
                  },
                  "#another-thing > .something"
              ],
              requirePaint: true
          }
      });
  • reporters (function, optional)

    Reporters that will get called when transition report is created. Reporters defined via reporters option are used only for single transition and are always executed in the end. They are useful in two cases:

    • appending additional information to a transition report, for example some application state that may influence measurement;
    • overwriting data supplied by global reporters.

      Reporters declared with this option should conform to the Reporter contract described in Reporters section below.

.find(conditions, callback)

Note: This is only supported on browsers where MutationObserver and Promise are available. On unsupported browsers it does nothing.

.find() is a utility method that finds elements in DOM. This is what .start({ready: ...}) uses underneath. It is useful for gathering timings of element availability:

metrics.find([
    ".issue-key"
]).then(function() {
    window.performacne && window.performance.mark('issue.visible');
});

Method returns a Promise, which is resolved after elements described by conditions are found. It will also execute callback passed as a second argument.

Conditions can be defined in two forms:

  1. Single selector - Promise is resolved when any element matches it
  2. Array of selectors - Promise is resolved when all elements are matched

As with the ready parameter of .start() method, additional hasNone parameter can be used. It means that Promise is resolved when there won't be any elements inside parent container (which is discovered using "selector") matching "hasNone".

metrics.find([
    {
        selector: '.parent-issue-container',
        hasNone: '.loading' // // <-- presence of this element inside "selector" indicates work is in progress
    },
    '.some-other-selector'
]).then(function() {
    window.performacne && window.performance.mark('issue.loaded');    
});

Push-state style navigation

Using the API you can also record push-state style navigation events:

var metrics = window["browser-metrics"];
$.on("a.rapid-board", "click", function (event) {
    metrics.start({key: "jira.rapid-board"});

    // bind to some app event that announces when a navigation is done, and call metrics.end({key: "jira.rapid-board"})
    // <some single-page-app style navigation>

    event.preventDefault();
});

Reporters

It's possible to include extra information for transition reports by writing a custom reporter. A simple use-case is including backend performance metrics for initial transitions (full page loads):

var metrics = window["browser-metrics"];
metrics.addReporter(function backendPerformanceReporter(transition) {
    var report = {};
    if (transition.isInitial) {
        report.backendRender = get_backend_render_time();
    }
    return report;
});

This example adds a backendRender property to the report object in the beacon for initial transitions.

Reporters are passed a Transition object that describes the transition that has just taken place, and must return a report. The exact API is as follows:

/**
 * @typedef {Object} Transition
 * @property {boolean} transition.isInitial True if the transition event was part of a full page load.
 * @property {string} transition.key An identifier for the transition.
 * @property {number} transition.end The number of milliseconds since UNIX epoch when the transition finished
 *     (either `.end()` was explicitly called or `.start({ready: ...})` was satisfied).
 * @property {number} transition.start The number of milliseconds since UNIX epoch when `.start()` was called.
 * @property {number} transition.threshold The maximum "tolerable" duration for the transition (in
 *     milliseconds).
 */

/**
 * @param {Transition} transition A description of the transition event that has just occurred.
 * @returns {Promise<object>|jQuery.Promise<object>|object} A hash of keys/values to contribute to the final analytics event.
 */
function Reporter(transition) { ... }

Be aware that there are limits on the size of analytics events. If you're concerned you may exceed these limits, chat to your nearest performance engineer.

A reporter returning a rejected promise is equivalent to it returning {}, i.e. the reporter simply does not contribute to the report.

Report fields

apdex

The apdex score for the transition.

This field is a convenience that precomputes the apdex based on the threshold and readyForUser fields. This field is included in every transition. As the apdex is for a single transition, the value is either 0, 0.5, 1.

Added in v1.61.1

Example

{
    apdex: 0.5
}

connectStart

The value of window.performance.timing.connectStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    connectStart: 1
}

connectEnd

The value of window.performance.timing.connectEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    connectEnd: 1
}

domainLookupEnd

The value of window.performance.timing.domainLookupEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domainLookupEnd: 1
}

domainLookupStart

The value of window.performance.timing.domainLookupStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domainLookupStart: 1
}

domContentLoadedEventStart

The value of window.performance.timing.domContentLoadedEventStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domContentLoadedEventStart: 1
}

domContentLoadedEventEnd

The value of window.performance.timing.domContentLoadedEventEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domContentLoadedEventEnd: 1
}

domComplete

The value of window.performance.timing.domComplete relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domComplete: 1
}

domLoading

The value of window.performance.timing.domLoading relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domLoading: 1
}

domInteractive

The value of window.performance.timing.domInteractive relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    domInteractive: 1
}

fetchStart

The value of window.performance.timing.fetchStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    fetchStart: 1
}

firstPaint

The time, relative to navigationStart, that the first paint of the page occurred. Depending on the browser different APIs are used:

  • Chrome -- window.chrome.loadTimes().firstPaintTime
  • Internet Explorer -- window.performance.timing.msFirstPaint

For other browsers firstPaint is not reported.

It's interesting to note in (at least) Chrome firstPaint does not have a value unless the tab is focused (i.e. switched to). This means that firstPaint may not always be present in browser-metrics reports.

Consider a scenario where a page is loaded in a background tab. It's possible for window.performance.timing.loadEventEnd to become non-zero (which is the earliest an initial report can finish) before the tab is ever presented to the user. Assuming no other reporters hold up the report, firstPaint will not be captured.

Example

{
    firstPaint: 674
}

isInitial

If true, indicates the transition was a full page load. Otherwise the value false is used.

Example

{
    isInitial: true
}

journeyId

A value that shared across multiple reports that come from transitions that occur within the same "page session". The definition of "page session" is dependent on the browser, as per their semantics of window.sessionStorage.

The intent behind this field is to provide a mechanism for tracking the path that a user takes through the application.

Example

{
    journeyId: "c8b37285-776b-4a70-94f3-41db9971775e"
}

key

A text key that identifies the transition. This value is pulled verbatim from the .start() API value.

Example

{
    key: "jira.issue.view"
}

loadEventStart

The value of window.performance.timing.loadEventStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    loadEventStart: 1
}

loadEventEnd

The value of window.performance.timing.loadEventEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    loadEventEnd: 1
}

navigationType

A number between 0 and 255 that's taken directly from window.performance.navigation.type.

On browsers that don't support this API, this field is not included in the report.

Example

{
    navigationType: 0
}

readyForUser

The number of milliseconds that it took for the transition to complete. For full page load transitions this value is relative to window.performance.timing.navigationStart, otherwise it's relative to when .start() was called.

A transition can become "complete" in two ways:

  1. The .stop() method is called.
  2. The ready option to .start() is used, and becomes satisfied.

Example

{
    readyForUser: 428
}

redirectCount

The number of HTTP redirects that occurred before finally loading the page. If the value is 0, this field is omitted from the report. This field is only ever present for full page load transitions, and is taken from the window.performance.navigation.redirectCount API.

Example

{
    redirectCount: 1
}

redirectEnd

The value of window.performance.timing.redirectEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    redirectEnd: 1
}

redirectStart

The value of window.performance.timing.redirectStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    redirectStart: 1
}

requestStart

The value of window.performance.timing.requestStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    requestStart: 1
}

resourceTiming

This field contains performance timings for each resource (excluding images) which finished downloading during the period of the transition, specifically:

resourceEntry.responseEnd >= transition.start
&& resourceEntry.responseEnd <= transition.end
&& resourceEntry.startTime >= transition.start

The start time for the resource is not intentionally not considered, as it would make some interactions hard to measure. For example consider a situation where a link hover initiates an AJAX request to be made, but the transition is only measured from a click.

Example

{
    resourceTiming: [
        {
            connectEnd: 172.3399999900721
            connectStart: 172.3399999900721
            domainLookupEnd: 172.3399999900721
            domainLookupStart: 172.3399999900721
            duration: 766.0440000181552
            fetchStart: 172.3399999900721
            initiatorType: "link"
            name: "http://localhost:8090/jira/s/cf68c932ec46dcad7a69c4c6a6ccaa49-CDN/en_AU-pi800d/71000/b6b48b2829824b869586ac216d119363/5.7.31/_/download/resources/com.atlassian.auiplugin:aui-reset/aui-reset.css"
            redirectEnd: 0
            redirectStart: 0
            requestStart: 900.1189999980852
            responseEnd: 938.3840000082273
            responseStart: 933.8010000064969
            secureConnectionStart: 0
            startTime: 172.3399999900721
        }
    ]
}

resourceLoadedEnd

This field contains the number of milliseconds it took for the last synchronous resource to finish loading prior to domContentLoadedEventStart. This field may also have the values:

  • 0 — all resources were cached (the value is 0 because in some browsers it's reported this way e.g. Chrome) it's possible that in other browsers this will be a non-zero value even when the resource was cached.
  • null — no external resources were required in the transition (prior to v5.0.4 0 was reported in this scenario).

This field is only included if:

Added in v2.0.0

Example

{
    resourceLoadedEnd: 428
}

resourceLoadedStart

This field contains the number of milliseconds it took for the first synchronous resource to start loading prior to domContentLoadedEventStart. This field may also have the values:

  • 0 — all resources were cached (the value is 0 because in some browsers it's reported this way e.g. Chrome) it's possible that in other browsers this will be a non-zero value even when the resource was cached.
  • null — no external resources were required in the transition.

This field is only included if:

Added in v5.3.0

Example

{
    resourceLoadedStart: 328
}

responseEnd

The value of window.performance.timing.responseEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    responseEnd: 3
}

responseStart

The value of window.performance.timing.responseStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    responseStart: 3
}

secureConnectionStart

The value of window.performance.timing.secureConnectionStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    secureConnectionStart: 3
}

threshold

Declares the target (in milliseconds) duration for the transition. The performance of the transition is considered good if it completes within this threshold. This value is taken from the option passed to .start().

The original motivation for this value was to facilitate the calculation of apdex (where we assume that good=threshold and tolerable=4*threshold. If we decide to incorporate other index calculations in the future, they can be based off of this threshold value too (but with a different weighting function than apdex).

Added in v1.61.1

Example

{
    threshold: 1000
}

unloadEventEnd

The value of window.performance.timing.unloadEventEnd relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    unloadEventEnd: 1
}

unloadEventStart

The value of window.performance.timing.unloadEventStart relative to window.performance.timing.navigationStart. If the value is 0 this field is omitted.

Example

{
    unloadEventStart: 3
}

userAgent

The user agent string of the browser, as seen from window.navigator.userAgent.

Example

{
    userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36"
}

userTiming

User timing API marks and measures that occurred during the transition. Note that not all browsers support performance.mark() (e.g. IE10) so you should probably write performance.mark && performance.mark("foo") to avoid breaking hard on legacy browsers.

Example

{
    marks: [
         {
             name: "my_mark",
             time: 111.11
         },
         {
             name: "my_mark",
             time: 222.22
         },
         {
             name: "my_mark_2",
             time: 333.33
         }
    ],
    measures: [
        {
            name: "my_measure",
            startTime: 444.44
            duration: 22
        },
        {
            name: "my_measure",
            startTime: 555.55
            duration: 33
        },
        {
            name: "my_measure_2",
            startTime: 666.66
            duration: 44
        }
    ]
}

Development

In the past lots of developers have had problems setting up a dev environment for browser-metrics, because of the many dependencies needed for building and testing. As a solution the project has moved to using Docker for development, so there are scripts in ./bin/ that proxy to useful commands.

Alternatively if you want a little more control, drop into a shell in the docker container:

$ ./bin/shell

Dependencies

You need to have docker installed then:

$ ./bin/install

This builds the docker container, and installs NPM, Bower and TSD dependencies.

If docker complains saying Cannot connect to the Docker daemon. Is the docker daemon running on this host? execute following in console:

docker-machine create --driver virtualbox default
eval "$(docker-machine env default)"

After first docker-machine create you can do just docker-machine start calls if system keeps complaining after you quit terminal:

docker-machine start default
eval "$(docker-machine env default)"

Tests

To run all the tests run:

$ ./bin/test

In the event they fail, you'll probably want a little more control over how they're run, so try:

$ ./bin/shell
# ./node_modules/.bin/karma start

This will start karma on port 9876, so make sure you have that port forwarded to your docker machine. Then load up http://localhost:9876 in a browser. The 'debug' button will run the tests in the local window's JS context, so you can debug with standard browser tools.

Packaging (building dist/)

$ ./bin/build

This will build three files:

  • dist/probe.js
  • dist/collector.js
  • dist/browser-metrics.d.ts (TypeScript definition)

Builds

https://engservices-bamboo.internal.atlassian.com/browse/BM-BM

Releasing

There's a Bamboo plan to do a release, but first you need to make sure that you've committed all the code changes that occur from:

$ ./bin/test
$ ./bin/build
$ ./bin/npm shrinkwrap

If your working directory is now dirty, you'll need to ensure those changes are correct and commit them before running the plan.

To run the plan:

  1. Browse to https://engservices-bamboo.internal.atlassian.com/browse/BM-BMR
  2. Choose Run → Run customised…
  3. Click "Override a variable"
  4. Make sure "version" is selected
  5. Change the value unset to the version you want (e.g. 5.0.4)
  6. CLick "Run" (Plan will bump version for you, no need to change it manually in package.json)

Demo

To facilitate testing browser-metrics, there's a demo that can be run. It's a simple express.js app:

./bin/demo

Then browse to http://localhost:3000 (make sure you have port 3000 forwarded).

Issues

Found an issue? Raise it on https://jdog.jira-dev.com/browse/BM

Change log

6.1.1

  • Check for window.performance before executing code that requires it.

6.1.0

  • Add requirePaint option that can be used with ready.
  • Fix resourceTiming to exclude resources that did not start within the transition.

6.0.0

  • Removed requireUpdate option from .start({ready: …}).
  • Fix bug in apdex calculation to adhere to the specification:

    • readyForUser < threshold = 1readyForUser <= threshold = 1
    • threshold <= readyForUser < (threshold × 4) = 0.5threshold < readyForUser <= (threshold × 4) = 1

5.3.0

  • Add resourceLoadedStart attribute that reports the earliest startTime of resources. This complements resourceLoadedEnd and allows us to improve the per-quantile-breakdown chunks by no longer assuming that resources start downloading at domLoading (which is a terrible assumption).

5.2.0

  • Added .find() API method that allows looking for specific elements in the DOM tree
  • reporters can now be specified per transition as a reporters start() option

5.1.0

  • hasNone for ready condition, which waits for absence of element(s) matching provided CSS selector(s) inside parent container (i.e. selector).

5.0.5

  • made firstPaint reporter work properly in iframe environment i.e. - it returns empty report, since browser doesn't provide firstPaint value in iframes.

5.0.4

  • resourceLoadedEnd reporter no longer reports the value 0 if no resources were found, and instead reports null, resolves BM-91.
  • The development environment now uses Docker, which should the issues that a lot of developers have been having with setting up browser-metrics for local development.
  • A Bamboo CI test plan has been setup.

5.0.3

  • Make collector.js use the bundled version of es6-promise, rather than looking for one on window. This fixes a bug in browsers that do not support window.Promise.

5.0.2

  • Switch collector.js and probe.js to be unminified versions, but add collector-min.js and probe-min.js which are minified.

5.0.1

  • Immediately attempt to drain the resource timing buffer on load, in case it's already full.

5.0.0

  • The resourceTiming reporter now includes resources that merely finished within a transition. Previously resources were also required to start within the transition. backwards incompatible

4.0.3

  • Add support for IE10 / IE11 / MSEdge / Firefox / Opera for the resourceTiming reporter. This was done by not requiring the window.performance.addEventListener to exist, and rather falling back to window.performnace.onresourcetimingbufferfull and assuming that exists.
  • Add a new test page to the demo, and added it (and the other existing page) to the navigation.
  • Fix bug for resourceTiming where some values may be null rather than 0 (affected IE 11).

4.0.2

  • Fixed broken 4.0.1 release.

4.0.1

  • Make .addReporter() API have higher priority than other APIs to ensure that reporters are added first. Note that this only has an effect prior to collector.js execution.

4.0.0

  • BM-31 — Remove ability to disable browser-metrics via WRM data provider (com.atlassian.plugins.browser.metrics.browser-metrics-plugin:browser-metrics.feature-data-provider-legacy). backwards incompatible
  • BM-85 — Remove legacy browser-metrics. backwards incompatible
  • The term "navigation" as-in NavigationEvent has been changed to transition. The intent is to have a general term that encompasses both "full page loads" and "other navigations". The problem with the term "navigation" is that it has an existing definition in the context of the Web which one might say is "when the URL changes". A "transition" is a much more generic term.
  • Transition objects have .start and .end attributes which are now relative to the navigationStart mark. Previously they were relative to UNIX epoch. backwards incompatible
  • For initial transitions, transition.start is now 0, indicating that the transition started at navigationStart. backwards incompatible
  • Removed the standalone demo that used herment, as browser-metrics is now agnostic to to all transport mechanisms.
  • Consolidated the other demos into a single express.js app.
  • Switched from Grunt to gulp.
  • Removed AMD style usage from documentation, instead promoting the window["browser-metrics"] global variable as it's compatible with async scripts.
  • Remove compression from the resourceTiming reporter, it is the responsibility of the consumer of browser-metrics to to appropriate compression. This was done as part of making the "data transport" not the responsibility of browser-metrics. It opens the door to allowing reports to be sanitised to be compliant with privacy policies (e.g. URLs may contain sensitive data). backwards incompatible
  • Numbers in reports are no longer rounded. Historically numbers have been rounded as a "lossy compression" mechanism to decrease the size of beacons. This is no longer the responsibilty of browser-metrics, and as such has been removed. This affects firstPaint, readyForUser, resourceTiming.
  • The report contributed by the resourceTiming reporter has been renamed from resourceTimings to resourceTiming. backwards incompatible
  • The new API .subscribe(function (beacon) { … }) has been added as a way of exfiltrating beacons from browser-metrics.
  • A large portion of tests have been migrated to jsverify rather than chance.js. This was done to improve test coverage by running each test 100 times with different values. The previous behaviour was to run each test once.
  • The resourceTiming reporter now collects resource timings for non-initial transitions, in addition to initial.
  • Integration with Atlassian Analytics has been removed, it is not the responsibility of the consumer to manage data transport/beaconing of data via the .subscribe() API method. backwards incompatible
  • browser-metrics is no longer a single browser-metrics.js file, but is now two separate files: backwards incompatible

    • probe.js -- a small script that must be loaded synchronously and provides window["browser-metrics"] APIs.
    • collector.js -- a larger script that may be loaded asynchronously, and effectively implements the behaviour of the probe.js APIs.
  • Removed bundling of es6-promise and MutationObserver polyfill from probe.js, but still bundling es6-promise in collector.js. The .start({ready: …}) API is a no-op unless MutationObserver and Promise APIs are available in the browser. backwards incompatible

  • .start({ready: …}) API is no longer deprecated, but rather usage is discouraged and a warning in the documentation has been added.
  • User Timing API marks and measures are both included in transition reports. This means that the performance.mark(<name>) and performance.measure(<name> <mark1Name>, <mark2Name>) can be used to detail important points in time for a transition.

3.3.0

  • Added resourceTimings reporter
  • Removed resourceDurations reporter

3.2.0

  • BM-79 — Only report firstPaint for initial transitions.
  • BM-42 — redirectCount reporter reports 0 when no redirects occurred, rather than being omitted from the report.
  • Use express.js for the almondjs demo and add redirect examples.

3.1.1

  • Add support for YUI compressor by avoiding the .catch() es6-promise method.
  • Add missing 3.1.0 version change log.

3.1.0

  • Added firstPaint reporter for Chrome and IE

3.0.0

  • Reporters that return a rejected promise no longer cause the entire report to be discarded, instead it's equilavent to the reporter returning an empty report, i.e. {}. (backwards incompatible)
  • Fix bug in resourceDurations and resourceLoadedEnd so that asynchronous scripts are no longer considered to be blocking DOMContentLoaded.

2.0.0

  • Remove resourceCount and slowResourceCount in favour of the more general purpose resourceDurations.

1.62.1

  • Round the resourceLoadedEnd value to an integer.

1.62.0

  • Add the resourceTiming reporter that adds resourceLoadedEnd, resourceCount, and slowResourceCount attributes.

1.61.0

  • Add threshold option to .start({...}).
  • Add apdex reporter.
  • Add threshold reporter.

1.60.1

  • Actually reports don't support any value type, they need to be string, boolean, or number.

1.60.0

  • Allow any value types in reports (just a TypeScript definition change).
  • Simplify the way Karma is configured.
7.0.2

6 years ago

7.0.1

6 years ago

7.0.0

6 years ago

6.1.7

7 years ago

6.1.6

7 years ago

6.1.5

7 years ago

6.1.4

7 years ago

6.1.3-3

7 years ago

6.1.3-2

7 years ago

6.1.3-1

7 years ago

6.1.3

7 years ago

6.1.2-1

7 years ago

6.1.2

7 years ago

6.1.1

7 years ago