Skip to main content
Deno 2 is finally here 🎉️
Learn more

@virtualstate/app-history

Native JavaScript app-history implementation

Support

Node.js supported Deno supported Chromium supported Webkit supported Firefox supported

Test Coverage

nycrc config on GitHub 95.23%25 lines covered 95.23%25 statements covered 92.65%25 functions covered 80.74%25 branches covered

Install

Snowpack

const { AppHistory } = await import("https://cdn.skypack.dev/@virtualstate/app-history");

Or

import { AppHistory } from "https://cdn.skypack.dev/@virtualstate/app-history";

npm / yarn / GitHub

npm i --save @virtualstate/app-history

Or

yarn add @virtualstate/app-history

Then

import { AppHistory } from "@virtualstate/app-history";
import { AppHistory } from "./app-history";

const appHistory = new AppHistory();

// Set initial url
appHistory.navigate("/");

appHistory.navigate("/skipped");

// Use .finished to wait for the transition to complete
await appHistory.navigate("/awaited").finished;

Waiting for events

import { AppHistory } from "./app-history";

const appHistory = new AppHistory();

appHistory.addEventListener("navigate", async ({ destination }) => {
    if (destination.url === "/disallow") {
        throw new Error("No!");
    }
});

await appHistory.navigate("/allowed").finished; // Resolves
await appHistory.navigate("/disallow").finished; // Rejects

Transitions

import { AppHistory } from "./app-history";
import { loadPhotoIntoCache } from "./cache";

const appHistory = new AppHistory();

appHistory.addEventListener("navigate", async ({ destination, transitionWhile }) => {
    transitionWhile(loadPhotoIntoCache(destination.url));
});

State

import { AppHistory } from "./app-history";

const appHistory = new AppHistory();

appHistory.addEventListener("currentchange", () => {
    console.log({ updatedState: appHistory.current?.getState() });
});

await appHistory.updateCurrent({
    state: {
        items: [
            "first",
            "second"
        ],
        index: 0
    }
}).finished;

await appHistory.updateCurrent({
    state: {
        ...appHistory.current.getState(),
        index: 1
    }
}).finished;

Updating browser url

This is a pending development task. The below code will help visually update the window

This can be achieved various ways, but if your application completely utilises the app history interface, then you can directly use pushState to immediately update the window’s url.

This does not take into account the browser’s native back/forward functionality, which would need to be investigated further.

import { AppHistory } from "./app-history";

const appHistory = new AppHistory();
const origin = typeof location === "undefined" ? "https://example.com" : location.origin;

appHistory.addEventListener("currentchange", () => {
    const { current } = appHistory;
    if (!current || !current.sameDocument) return;
    const state = current.getState() ?? {};
    const { pathname } = new URL(current.url, origin);
    if (typeof window !== "undefined" && window.history) {
        window.history.pushState(state, state.title, origin)
    }
})