class Router { #routes = []; on(pattern, handler) { const regex = new RegExp( '^' + pattern.replace(/:([^/]+)/g, '(?<$1>[^/]+)') + '$' ); this.#routes.push({ regex, handler }); return this; } navigate(path) { location.hash = '#' + path; } start() { const dispatch = () => { const path = decodeURIComponent(location.hash.slice(1)) || '/'; for (const { regex, handler } of this.#routes) { const m = path.match(regex); if (m) { handler(m.groups || {}); return; } } }; window.addEventListener('hashchange', dispatch); dispatch(); } get current() { return decodeURIComponent(location.hash.slice(1)) || '/'; } } export const router = new Router();