Soft navigations

Measure single page app route changes as navigation steps with @push-based/lighthouse-soft-navigation.

4 min read 6 sections

On this pageInstallation

A soft navigation is a route change that updates the URL and the content without loading a new document, like a single page app does on a link click. Stock Lighthouse can't measure one as a navigation step: it waits for a page load that never comes and fails with NO_FCP.

@push-based/lighthouse-soft-navigation is a Lighthouse config that measures it as a navigation step, from the click, with FCP, LCP and a Performance score. Pass it as the config of a flow, and its soft navigation steps show up in every user-flow report next to page loads, timespans and snapshots.

This page covers the user-flow setup. How soft navigation steps are recognised and measured, and their limits, are in the lighthouse-soft-navigation docs.

Installation

npm install --save-dev @push-based/user-flow @push-based/lighthouse-soft-navigation

The gatherers of the package extend the stock gatherers of the Lighthouse they import, so user-flow and the package have to share one copy of Lighthouse. Both depend on lighthouse@^13.6.0, so it is installed once. npm ls lighthouse shows a single version.

Flow file

user-flows/checkout.uf.mts
import { softNavigationConfig } from '@push-based/lighthouse-soft-navigation';
import type { UserFlowProvider } from '@push-based/user-flow';

const observed = { throttlingMethod: 'devtools' } as const;

export default {
  flowOptions: { name: 'Checkout', config: softNavigationConfig() },
  interactions: async ({ flow, page, collectOptions }) => {
    // A page load, measured by stock Lighthouse.
    await flow.navigate(collectOptions.url);

    // A soft navigation.
    await flow.navigate(async () => {
      await page.click('a.product-link');
    }, observed);

    // The same with startNavigation/endNavigation.
    await flow.startNavigation(observed);
    await page.click('a.checkout-link');
    await flow.endNavigation();
  },
} satisfies UserFlowProvider;
Terminal
npx user-flow collect --url https://example.com --ufPath ./user-flows
  • The config goes in flowOptions.config. collect.config and collect.configPath in .user-flowrc.json and --configPath take JSON, which can't hold the gatherer and audit classes of the package.
  • A soft navigation step is a navigation step whose interaction stays in the document. See Soft navigation steps.
  • A soft navigation step passes throttlingMethod: 'devtools' or 'provided', since simulated throttling needs a document request. See Throttling.

Settings

softNavigationConfig() returns a complete config, so user-flow runs it as written and only takes settings from the project. Settings for every flow go in collect.config of .user-flowrc.json, or in the file passed with --configPath:

.user-flowrc.json
{
  "collect": {
    "config": {
      "settings": {
        "throttlingMethod": "devtools",
        "onlyCategories": ["performance"]
      }
    }
  }
}

With throttlingMethod set for the project, the steps don't need to pass it. Page loads then run with DevTools throttling too; Throttling explains the trade-off.

Settings for one flow go in its config, through softNavigationConfig. They take precedence over the settings of the project:

TypeScript
config: softNavigationConfig({
  extends: 'lighthouse:default',
  settings: { onlyCategories: ['performance'] },
}),

Recordings

A Chrome DevTools recording replayed with createUserFlowRunner measures a soft navigation with startNavigation and endNavigation steps. The throttling method goes in stepOptions:

products.replay.json
{
  "title": "Open a product",
  "steps": [
    {
      "type": "startNavigation",
      "stepOptions": { "throttlingMethod": "devtools" }
    },
    {
      "type": "click",
      "selectors": [["a.product-link"]],
      "offsetX": 5,
      "offsetY": 5
    },
    { "type": "endNavigation" }
  ]
}

See DevTools Recorder exports for replaying recordings.

Reports

A soft navigation step is a navigation step, so the HTML, JSON and Markdown reports show it like a page load: gather mode navigation, with a Performance score. The soft-navigation audit tells the two apart. See Reading the results.

Dry runs

--dryRun fails for a flow that navigates with a callback or calls startNavigation, which every soft navigation does. The dry run stand-in doesn't support either yet; see #355.

All pages

  • Getting started Introduction Introduction What @push-based/user-flow is, why it exists and what it gives you out of the box.
  • Getting started Installation Installation Install the CLI in an existing project, run it without installing, or start from an empty folder.
  • Getting started Quick start Quick start Initialise a config, generate a first user flow and open your first Lighthouse report in minutes.
  • CLI reference Overview and global options Overview and global options The command structure, the global options every command accepts and how the rc file fits in.
  • CLI reference init command init command Create or update a .user-flowrc.json and scaffold an example flow or a GitHub workflow.
  • CLI reference collect command collect command Execute user flows against a URL, pick report formats and speed up development with dry runs.
  • CLI reference Report formats and viewer Report formats and viewer HTML, JSON, Markdown and stdout reports, and how to open them in the Lighthouse viewer.
  • CLI reference Lighthouse configuration Lighthouse configuration Pass a Lighthouse config globally through the rc file or the CLI, or locally per flow.
  • CLI reference Prompts and debugging Prompts and debugging Keyboard shortcuts for prompts, multi-value options, boolean negation and verbose logging.
  • Writing user flows Basic user flows Basic user flows The three Lighthouse measurement modes and how to combine navigation, timespan and snapshot steps.
  • Writing user flows UFO architecture UFO architecture Keep larger test suites maintainable with fixtures, user flow objects and thin flow files.
  • Writing user flows DevTools Recorder exports DevTools Recorder exports Record a flow in Chrome DevTools, export it as JSON and replay it with measurement steps.
  • Integrations GitHub workflow GitHub workflow Run user flows on every pull request and post the Markdown report as a sticky PR comment.
  • Integrations Nx plugin Nx plugin Generators and an executor that make user flows a first-class target in an Nx workspace.
  • Integrations Soft navigations Soft navigations Measure single page app route changes as navigation steps with @push-based/lighthouse-soft-navigation.
  • Resources Examples and links Examples and links Example repositories, the Lighthouse viewer and further reading on user flows.