@tanstack/vue-router
Version:
Modern and scalable routing for Vue applications
148 lines (147 loc) • 6.78 kB
JavaScript
import { nonRouteComponentContext, renderInNonRouteComponentContext } from "./nonRouteComponentContext.js";
import { CatchBoundary } from "./CatchBoundary.js";
import { useRouter } from "./useRouter.js";
import { routeIdContext } from "./matchContext.js";
import { ClientOnly } from "./ClientOnly.js";
import { CatchNotFound } from "./not-found.js";
import { renderRouteNotFound } from "./renderRouteNotFound.js";
import { ScrollRestoration } from "./scroll-restoration.js";
import { isNotFound, rootRouteId } from "@tanstack/router-core";
import * as Vue from "vue";
import { isServer } from "@tanstack/router-core/isServer";
import { useStore } from "@tanstack/vue-store";
//#region src/Match.tsx
var Match = Vue.defineComponent({
name: "Match",
props: { routeId: {
type: String,
required: true
} },
setup(props) {
const router = useRouter();
const routeId = props.routeId;
const activeMatch = useStore(router.stores.getMatchStore(routeId), (value) => value, { equal: Object.is });
Vue.provide(routeIdContext, routeId);
return () => {
const match = activeMatch.value;
const route = match ? router.routesById[routeId] : void 0;
const PendingComponent = route?.options.pendingComponent ?? router.options.defaultPendingComponent;
const pendingElement = PendingComponent ? process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(PendingComponent, void 0, "pendingComponent") : Vue.h(PendingComponent) : void 0;
const routeErrorComponent = route?.options.errorComponent ?? router.options.defaultErrorComponent;
const routeOnCatch = route?.options.onCatch ?? router.options.defaultOnCatch;
const routeNotFoundComponent = route?.isRoot ? route.options.notFoundComponent ?? router.options.notFoundRoute?.options.component : route?.options.notFoundComponent;
const ShellComponent = route?.isRoot ? route.options.shellComponent : void 0;
const resolvedNoSsr = match?.ssr === false || match?.ssr === "data-only";
const renderMatchContent = () => {
const matchInner = Vue.h(MatchInner);
let content = resolvedNoSsr ? Vue.h(ClientOnly, { fallback: pendingElement }, { default: () => matchInner }) : matchInner;
if (routeNotFoundComponent) content = Vue.h(CatchNotFound, {
fallback: (error) => {
error.routeId ??= routeId;
if (error.routeId !== routeId) throw error;
return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(routeNotFoundComponent, error, "notFoundComponent") : Vue.h(routeNotFoundComponent, error);
},
children: content
});
if (routeErrorComponent) content = CatchBoundary({
getResetKey: () => activeMatch.value,
errorComponent: routeErrorComponent,
onCatch: (error) => {
if (isNotFound(error)) {
error.routeId ??= routeId;
throw error;
}
if (process.env.NODE_ENV !== "production") console.warn(`Warning: Error in route match: ${match?.id}`);
routeOnCatch?.(error);
},
children: content
});
if (route?.parentRoute?.id !== rootRouteId) return content;
return Vue.h(Vue.Fragment, null, [content, Vue.h(Vue.Fragment, null, [(isServer ?? router.isServer) && router.options.scrollRestoration ? Vue.h(ScrollRestoration) : null])]);
};
if (!ShellComponent) return renderMatchContent();
return Vue.h(ShellComponent, null, { default: () => renderMatchContent() });
};
}
});
var MatchInner = Vue.defineComponent({
name: "MatchInner",
setup() {
const router = useRouter();
const routeId = Vue.inject(routeIdContext);
const activeMatch = useStore(router.stores.getMatchStore(routeId));
const combinedState = Vue.computed(() => {
const match = activeMatch.value;
if (!match) return null;
const matchRouteId = match.routeId;
const remountFn = router.routesById[matchRouteId].options.remountDeps ?? router.options.defaultRemountDeps;
const remountDeps = remountFn ? remountFn({
routeId: matchRouteId,
loaderDeps: match.loaderDeps,
params: match._strictParams,
search: match._strictSearch
}) : void 0;
return [match, remountDeps ? JSON.stringify(remountDeps) : void 0];
});
return () => {
const state = combinedState.value;
if (!state) return null;
const [match, remountKey] = state;
const route = router.routesById[match.routeId];
if (match.status === "notFound") return renderRouteNotFound(router, route, match.error);
if (match.status === "error") {
const RouteErrorComponent = route.options.errorComponent ?? router.options.defaultErrorComponent;
if (RouteErrorComponent) {
const errorProps = {
error: match.error,
reset: () => {
router.invalidate();
},
info: { componentStack: "" }
};
return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(RouteErrorComponent, errorProps, "errorComponent") : Vue.h(RouteErrorComponent, errorProps);
}
throw match.error;
}
if (match.status === "pending") {
const PendingComponent = route.options.pendingComponent ?? router.options.defaultPendingComponent;
if (PendingComponent) return process.env.NODE_ENV !== "production" ? renderInNonRouteComponentContext(PendingComponent, void 0, "pendingComponent") : Vue.h(PendingComponent);
return null;
}
const Comp = route.options.component ?? router.options.defaultComponent;
if (Comp) return Vue.h(Comp, remountKey !== void 0 ? { key: remountKey } : void 0);
return Vue.h(Outlet, remountKey !== void 0 ? { key: remountKey } : void 0);
};
}
});
var Outlet = Vue.defineComponent({
name: "Outlet",
setup() {
if (process.env.NODE_ENV !== "production") {
const nonRouteComponent = Vue.inject(nonRouteComponentContext, void 0);
if (nonRouteComponent) Vue.watch(nonRouteComponent, (component) => {
console.warn(`Warning: An <Outlet /> was rendered inside a ${component}. <Outlet /> should only be rendered inside a route component.`);
}, { immediate: true });
}
const router = useRouter();
const parentRouteId = Vue.inject(routeIdContext);
const parentMatch = useStore(router.stores.getMatchStore(parentRouteId));
const route = router.routesById[parentRouteId];
const childMatch = useStore(router.stores.matches, (matches) => {
const child = matches[matches.findIndex((match) => match.routeId === parentRouteId) + 1];
return child ? [child.routeId, child.routeId + JSON.stringify(child._strictParams)] : void 0;
});
return () => {
if (parentMatch.value?._notFound) return renderRouteNotFound(router, route, parentMatch.value.error);
const child = childMatch.value;
if (!child) return null;
return Vue.h(Match, {
routeId: child[0],
key: child[1]
});
};
}
});
//#endregion
export { Match, Outlet };
//# sourceMappingURL=Match.js.map