Skip to content

Rework how runs start, stop and finish - #569

Merged
CodeByZach merged 4 commits into
candidate-2.0from
lifecycle
Nov 8, 2026
Merged

CodeByZach merged 4 commits into
candidate-2.0from
lifecycle

Conversation

@CodeByZach

Copy link
Copy Markdown
Owner

Reworks how pace starts, stops, restarts and finishes a run. The commit message lists each change; in short:

  • Pace.stop() really stops: no done or hide afterwards, no bar coming back, and <body> gets pace-done.
  • Restarting mid-run leaves one animation, and Pace.start() while a run is in progress only stores its options.
  • Each run fires start, done and hide once. A request or navigation while the bar is finishing starts a new run instead of being lost.
  • Collectors are created per run from the options of that Pace.start() call and cleaned up afterwards, so restarts no longer pile up listeners and timers.
  • The bar no longer finishes early when requests or selectors complete in a different order than they started (a regression since 1.2.0).
  • A page that sets document.onreadystatechange no longer leaves the bar stuck.
  • Errors in collectors or during a navigation restart can't leave pace stuck or stop the page's navigation.

Also brings in master (the anchored .gitattributes patterns).

Tests: tests/lifecycle.spec.mjs, one test per case, each failing on the previous code. The README's API section describes the new start() and stop() behavior.

Without a leading slash, "pace.min.js" and "pace-theme-default.min.css"
match files of that name in any folder. Anchoring them limits the
attribute to the two files the build writes. themes/** already only
matches the root themes folder. The same 152 files are marked.
Mark only the root min files as generated
Brings in the anchored .gitattributes patterns.
A run now goes from waiting (for the target element) to running to
finishing (done, about to hide), and only one exists at a time:

- Pace.stop() cancels everything the run scheduled, removes the bar and
  marks <body> pace-done. Before, the animation and the pending hide kept
  going, so the bar came back and fired done and hide.
- Pace.restart() mid-run no longer leaves a second animation running, and
  Pace.start() while a run is in progress only stores its options.
- Each run fires start, done and hide once. A request or navigation while
  the bar is finishing starts a new run; before, the old run's hide timer
  hid the new run, and requests opened in that window were not shown.
- When the restartOnRequestAfter check finds a run in progress, the request
  joins that run instead of restarting it.
- Collectors are created when a run starts, from the options of that call,
  and stopped when it is done. Before, every restart added listeners and
  timers that were never removed, and options passed to Pace.start() only
  applied from the next run.
- Each tracked request or element keeps its own progress state. Before, a
  finished request or element passed its state to the next one by list
  position, so the bar could finish while requests were still loading or
  selectors were still missing (since 1.2.0).
- The document collector listens for readystatechange instead of
  assigning document.onreadystatechange, so a page that sets that property
  no longer leaves the bar stuck.
- <body> classes change through classList, without duplicates.
- A collector or extra source that throws leaves pace idle, and an error
  during a pushState or replaceState restart is reported instead of
  stopping the page's navigation.

The animation runs on requestAnimationFrame at about 30 frames a second.
Pace.go and the internal NoTargetError are gone.
@CodeByZach
CodeByZach merged commit adfc950 into candidate-2.0 Nov 8, 2026
2 checks passed
@CodeByZach
CodeByZach deleted the lifecycle branch November 8, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant