Progress bar like NProgress in 90 lines of code (vs NProgress v0.2.0 is 470 lines .js + 70 lines .css):
import { useEffect, useReducer, useRef } from 'react';
import { assert } from './assert';
import { wait } from './wait';
import { getRandomInt } from './getRandomNumber';
let waitController: AbortController | undefined;
// https://gist.github.com/tkrotoff/db8a8106cc93ae797ea968d78ea28047
export function useProgressBar({
  trickleMaxWidth = 94,
  trickleIncrementMin = 1,
  trickleIncrementMax = 5,
  dropMinSpeed = 50,
  dropMaxSpeed = 150,
  transitionSpeed = 600
} = {}) {
  // https://stackoverflow.com/a/66436476
  const [, forceUpdate] = useReducer(x => x + 1, 0);
  // https://github.com/facebook/react/issues/14010#issuecomment-433788147
  const widthRef = useRef(0);
  function setWidth(value: number) {
    widthRef.current = value;
    forceUpdate();
  }
  async function trickle() {
    if (widthRef.current < trickleMaxWidth) {
      const inc =
        widthRef.current +
        getRandomInt(trickleIncrementMin, trickleIncrementMax); // ~3
      setWidth(inc);
      try {
        await wait(getRandomInt(dropMinSpeed, dropMaxSpeed) /* ~100 ms */, {
          signal: waitController!.signal
        });
        await trickle();
      } catch {
        // Current loop aborted: a new route has been started
      }
    }
  }
  async function start() {
    // Abort current loops if any: a new route has been started
    waitController?.abort();
    waitController = new AbortController();
    // Force the show the JSX
    setWidth(1);
    await wait(0);
    await trickle();
  }
  async function complete() {
    assert(
      waitController !== undefined,
      'Make sure start() is called before calling complete()'
    );
    setWidth(100);
    try {
      await wait(transitionSpeed, { signal: waitController.signal });
      setWidth(0);
    } catch {
      // Current loop aborted: a new route has been started
    }
  }
  function reset() {
    // Abort current loops if any
    waitController?.abort();
    setWidth(0);
  }
  useEffect(() => {
    return () => {
      // Abort current loops if any
      waitController?.abort();
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return {
    start,
    complete,
    reset,
    width: widthRef.current
  };
}
import { useRouter } from 'next/router';
import { useEffect } from 'react';
import { useProgressBar } from './useProgressBar';
const transitionSpeed = 600;
// https://gist.github.com/tkrotoff/db8a8106cc93ae797ea968d78ea28047
export function RouterProgressBar(
  props?: Parameters<typeof useProgressBar>[0]
) {
  const { events } = useRouter();
  const { width, start, complete, reset } = useProgressBar({
    transitionSpeed,
    ...props
  });
  useEffect(() => {
    events.on('routeChangeStart', start);
    events.on('routeChangeComplete', complete);
    events.on('routeChangeError', reset); // Typical case: "Route Cancelled"
    return () => {
      events.off('routeChangeStart', start);
      events.off('routeChangeComplete', complete);
      events.off('routeChangeError', reset);
    };
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);
  return width > 0 ? (
    // Use Bootstrap, Material UI, Tailwind CSS... to style the progress bar
    <div
      className="progress fixed-top bg-transparent rounded-0"
      style={{
        height: 3, // GitHub turbo-progress-bar height is 3px
        zIndex: 1091 // $zindex-toast + 1 => always visible
      }}
    >
      <div
        className="progress-bar"
        style={{
          width: `${width}%`,
          //transition: 'none',
          transition: `width ${width > 1 ? transitionSpeed : 0}ms ease`
        }}
      />
    </div>
  ) : null;
}
How to use:
// pages/_app.tsx
import { AppProps } from 'next/app';
import Head from 'next/head';
import { RouterProgressBar } from './RouterProgressBar';
export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Head>
        <title>My title</title>
        <meta name="description" content="My description" />
      </Head>
      <RouterProgressBar />
      <Component {...pageProps} />
    </>
  );
}
More here: https://gist.github.com/tkrotoff/db8a8106cc93ae797ea968d78ea28047