Navigation Utilities (navigation-utils.js)
Examine link destination parsers, external route filters, and trailing-slash route normalizations.
Key File Location: ./dinou/core/navigation-utils.js💡 Overview
When a user clicks a link (like <Link href="/about">), the client router must hijack the click, resolve the destination, and update page states. If the link points to an external site or a mailto link, the router must bypass interception and let the browser load the link normally.
The navigation-utils.js file exposes helpers to detect external links and normalize paths for consistent cache matching.
⚡ Routing Safety Checks
The utilities provide two key features:
- External Link Identification: Filters out non-HTTP schemes (e.g.
mailto:,tel:,javascript:) and external domains, preventing the SPA router from intercepting them. - Trailing Slash Standardization: Strips trailing slashes from pathnames (e.g. converting
/docs/to/docs) to prevent duplicate route cache records.
⚙️ Complete Code Walkthrough
Below is the full, complete code of navigation-utils.js:
export function isExternalUrl(href) {
if (!href) return false;
// 1. Protocol-relative (e.g. //google.com)
if (href.startsWith("//")) {
return true;
}
// 2. Absolute with protocol (e.g. https://google.com)
if (href.includes("://")) {
try {
const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
const url = new URL(href, origin);
return url.origin !== origin;
} catch (e) {
return true;
}
}
// 3. Non-http protocols (mailto:, tel:, javascript:)
if (
/^[a-zA-Z0-9+-.]+:[^//]/.test(href) ||
href.startsWith("mailto:") ||
href.startsWith("tel:") ||
href.startsWith("javascript:")
) {
return true;
}
return false;
}
export function resolveUrl(href, currentPathname) {
if (isExternalUrl(href)) {
return href;
}
const origin = typeof window !== "undefined" ? window.location.origin : "http://localhost";
if (href.startsWith("/") || href.includes("://")) {
const url = new URL(href, origin);
return normalize(url.pathname + url.search + url.hash);
}
let base = currentPathname;
if (!base.endsWith("/")) base += "/";
const resolved = new URL(href, origin + base);
return normalize(resolved.pathname + resolved.search + resolved.hash);
}
// 4. Trailing slash normalizer: prevents duplicate route cache records
function normalize(path) {
if (
path.length > 1 &&
path.endsWith("/") &&
!path.includes("?") &&
!path.includes("#")
) {
return path.slice(0, -1);
}
return path;
}