Skip to the solution
MediumFrontend11 min read

How do you set up Vue Router (routes, RouterLink, RouterView, history modes)?

632 views

The problem

Question presented to candidate: "We are adding pages to a Vue 3 single-page app. Walk me through setting up Vue Router from scratch: where routes are defined, how links and the page outlet work, and which history mode you would pick for production."

What a strong answer should cover:

  • createRouter({ history, routes }) plus app.use(router); each route record maps a path (and ideally a name) to a component.
  • <RouterView /> is the outlet that renders the matched component; <RouterLink> renders a real <a> that navigates without a page reload and gets router-link-active / router-link-exact-active classes.
  • The three histories: createWebHistory (clean URLs, needs a server fallback to index.html), createWebHashHistory (#/about, no server config, worse for SEO), createMemoryHistory (SSR and tests).
  • Lazy-loaded route components with () => import(...) so each page is its own chunk, and a catch-all /:pathMatch(.*)* route for 404s.
  • Current versions: Vue Router 5 is a drop-in upgrade from 4 for code-based routes; file-based routing moved into the core package.

Clarifying questions expected:

  • "Where is this deployed, and can we configure the server to fall back to index.html?"
  • "Do we need SSR or SEO for these pages?"

Code / implementation expected: Yes β€” a router module with a few routes (one lazy, one catch-all), app.use(router), and an App.vue with RouterLink and RouterView.

  • vue
  • vue-router
  • routing

Try it yourself

Sketch your approach before you read the solution. That is what the interview tests.

Stuck? Get a hint.

A short nudge toward the approach. It will not give the answer away.

Solution

The solution is hidden so you can try first

11 min read Β· 10 sections

Read the code

VueWhat a router does, with no library: a hash router in one SFC
<script setup>
// What a router does, in 20 lines and with no library: map a URL to a
// component and re-render when the URL changes. Vue Router adds nested
// routes, params, guards, history modes and lazy loading on top of this idea.
import { ref, computed, defineComponent, h, onMounted, onUnmounted } from "vue";

const Home = defineComponent({ render: () => h("h2", "Home page") });
const About = defineComponent({ render: () => h("h2", "About page") });
const NotFound = defineComponent({ render: () => h("h2", "404: no route matches") });

const routes = { "/": Home, "/about": About };

const currentPath = ref(window.location.hash.slice(1) || "/");
const onHashChange = () => (currentPath.value = window.location.hash.slice(1) || "/");
onMounted(() => window.addEventListener("hashchange", onHashChange));
onUnmounted(() => window.removeEventListener("hashchange", onHashChange));

// The "RouterView": whichever component matches the current path
const currentView = computed(() => routes[currentPath.value] ?? NotFound);
</script>

<template>
  <nav>
    <a href="#/" :class="{ active: currentPath === '/' }">Home</a> |
    <a href="#/about" :class="{ active: currentPath === '/about' }">About</a> |
    <a href="#/missing">Broken link</a>
  </nav>
  <component :is="currentView" />
  <p>current path: {{ currentPath }}</p>
</template>
A real Vue Router 5 setup: router module and main.js
// src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";

export const router = createRouter({
  // HTML5 history: clean URLs like /about (needs a server fallback to index.html)
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    { path: "/", name: "home", component: HomeView },
    // Lazy-loaded: this view becomes its own chunk, fetched on first visit
    { path: "/about", name: "about", component: () => import("../views/AboutView.vue") },
    // Catch-all 404: must match anything the routes above did not
    { path: "/:pathMatch(.*)*", name: "not-found", component: () => import("../views/NotFound.vue") },
  ],
});

// src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import { router } from "./router";

createApp(App).use(router).mount("#app");

Discussion

Other approaches, follow-ups and how it went in real interviews.

Sign in to join the discussion.

No comments yet. Share how you would answer it.

Question 44 of 92 in Vue.js

Keep your momentum going.

Mark this question solved to track your progress, then take the next one while it is fresh.

All Vue.js questions
Up nextMedium

What is the difference between computed and watch?

Continue