nuxt
Version:
[](https://nuxt.com)
162 lines (161 loc) • 5.74 kB
JavaScript
import { getCurrentInstance, hasInjectionContext, inject, onUnmounted } from "vue";
import { sanitizeStatusCode } from "h3";
import { hasProtocol, joinURL, parseURL, withQuery } from "ufo";
import { useNuxtApp, useRuntimeConfig } from "../nuxt.js";
import { createError, showError } from "./error.js";
import { useState } from "./state.js";
export const useRouter = () => {
return useNuxtApp()?.$router;
};
export const useRoute = () => {
if (process.dev && isProcessingMiddleware()) {
console.warn("[nuxt] Calling `useRoute` within middleware may lead to misleading results. Instead, use the (to, from) arguments passed to the middleware to access the new and old routes.");
}
if (hasInjectionContext()) {
return inject("_route", useNuxtApp()._route);
}
return useNuxtApp()._route;
};
export const onBeforeRouteLeave = (guard) => {
const unsubscribe = useRouter().beforeEach((to, from, next) => {
if (to === from) {
return;
}
return guard(to, from, next);
});
onUnmounted(unsubscribe);
};
export const onBeforeRouteUpdate = (guard) => {
const unsubscribe = useRouter().beforeEach(guard);
onUnmounted(unsubscribe);
};
/*! @__NO_SIDE_EFFECTS__ */
export function defineNuxtRouteMiddleware(middleware) {
return middleware;
}
export const addRouteMiddleware = (name, middleware, options = {}) => {
const nuxtApp = useNuxtApp();
const global = options.global || typeof name !== "string";
const mw = typeof name !== "string" ? name : middleware;
if (!mw) {
console.warn("[nuxt] No route middleware passed to `addRouteMiddleware`.", name);
return;
}
if (global) {
nuxtApp._middleware.global.push(mw);
} else {
nuxtApp._middleware.named[name] = mw;
}
};
const isProcessingMiddleware = () => {
try {
if (useNuxtApp()._processingMiddleware) {
return true;
}
} catch {
return true;
}
return false;
};
export const navigateTo = (to, options) => {
if (!to) {
to = "/";
}
const toPath = typeof to === "string" ? to : withQuery(to.path || "/", to.query || {}) + (to.hash || "");
if (options?.open) {
if (process.client) {
const { target = "_blank", windowFeatures = {} } = options.open;
const features = Object.entries(windowFeatures).filter(([_, value]) => value !== void 0).map(([feature, value]) => `${feature.toLowerCase()}=${value}`).join(", ");
open(toPath, target, features);
}
return Promise.resolve();
}
const isExternal = options?.external || hasProtocol(toPath, { acceptRelative: true });
if (isExternal && !options?.external) {
throw new Error("Navigating to external URL is not allowed by default. Use `navigateTo (url, { external: true })`.");
}
if (isExternal && parseURL(toPath).protocol === "script:") {
throw new Error("Cannot navigate to an URL with script protocol.");
}
const inMiddleware = isProcessingMiddleware();
if (process.client && !isExternal && inMiddleware) {
return to;
}
const router = useRouter();
const nuxtApp = useNuxtApp();
if (process.server) {
if (nuxtApp.ssrContext) {
const fullPath = typeof to === "string" || isExternal ? toPath : router.resolve(to).fullPath || "/";
const location2 = isExternal ? toPath : joinURL(useRuntimeConfig().app.baseURL, fullPath);
async function redirect(response) {
await nuxtApp.callHook("app:redirected");
const encodedLoc = location2.replace(/"/g, "%22");
nuxtApp.ssrContext._renderResponse = {
statusCode: sanitizeStatusCode(options?.redirectCode || 302, 302),
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
headers: { location: location2 }
};
return response;
}
if (!isExternal && inMiddleware) {
router.afterEach((final) => final.fullPath === fullPath ? redirect(false) : void 0);
return to;
}
return redirect(!inMiddleware ? void 0 : (
/* abort route navigation */
false
));
}
}
if (isExternal) {
if (options?.replace) {
location.replace(toPath);
} else {
location.href = toPath;
}
if (inMiddleware) {
if (!nuxtApp.isHydrating) {
return false;
}
return new Promise(() => {
});
}
return Promise.resolve();
}
return options?.replace ? router.replace(to) : router.push(to);
};
export const abortNavigation = (err) => {
if (process.dev && !isProcessingMiddleware()) {
throw new Error("abortNavigation() is only usable inside a route middleware handler.");
}
if (!err) {
return false;
}
err = createError(err);
if (err.fatal) {
useNuxtApp().runWithContext(() => showError(err));
}
throw err;
};
export const setPageLayout = (layout) => {
if (process.server) {
if (process.dev && getCurrentInstance() && useState("_layout").value !== layout) {
console.warn("[warn] [nuxt] `setPageLayout` should not be called to change the layout on the server within a component as this will cause hydration errors.");
}
useState("_layout").value = layout;
}
const nuxtApp = useNuxtApp();
if (process.dev && nuxtApp.isHydrating && nuxtApp.payload.serverRendered && useState("_layout").value !== layout) {
console.warn("[warn] [nuxt] `setPageLayout` should not be called to change the layout during hydration as this will cause hydration errors.");
}
const inMiddleware = isProcessingMiddleware();
if (inMiddleware || process.server || nuxtApp.isHydrating) {
const unsubscribe = useRouter().beforeResolve((to) => {
to.meta.layout = layout;
unsubscribe();
});
}
if (!inMiddleware) {
useRoute().meta.layout = layout;
}
};