In Vue Router 5, when a user leaves an HR edit form for a lazily loaded payroll route with `beforeEnter`, in what order do the guards run, and where does `beforeResolve` fit?
answer
- leave first, after-hooks last
- global, reused, entering
- chunks load before beforeRouteEnter
- beforeResolve just before confirming
- next(vm) callbacks after mount
basics
~10 sLeave guards of the edit form, global beforeEach, update guards of reused components, the payroll record's beforeEnter, the lazy component loads, its beforeRouteEnter, global beforeResolve, confirmation, afterEach, the DOM update, then next(vm) callbacks.
solid answer
~40 sVue Router 5 runs guards in a fixed pipeline. First the leave guards of components being left, so the edit form can refuse. Then global `beforeEach` guards in registration order; then update guards of components that stay mounted; then `beforeEnter` of the records being entered, parent before child. Next it resolves lazy route components and runs their `beforeRouteEnter`. Last before confirmation come global `beforeResolve` guards, which therefore see a navigation every other guard has accepted and every chunk has loaded; that makes them the place for permission prompts or fetches you only want for a page the user will actually enter. After confirmation `afterEach` hooks run, they cannot change anything, the DOM updates, and callbacks passed to `next(vm)` in `beforeRouteEnter` receive the mounted instance. Any guard that cancels, redirects or throws stops the rest.
code
ts · 19 linesrouter.beforeEach((to) => {
console.log('3 beforeEach', to.fullPath)
})
router.beforeResolve((to) => {
console.log('8 beforeResolve', to.fullPath)
})
router.afterEach((to, from, failure) => {
console.log('10 afterEach', failure ? 'failed' : 'ok')
})
export const routes = [
{
path: '/payroll',
component: () => import('@/pages/Payroll.vue'),
beforeEnter: [requireOpenPeriod, requirePayrollRole],
},
]go deeper
Recall that there are global, per-route and in-component guards, and that afterEach runs after the navigation has finished.
Explain where beforeEnter and beforeResolve sit, and why beforeEnter is skipped for param changes and between sibling children.
Reason from the pipeline: authentication before chunks load, expensive work in beforeResolve, next(vm) only in beforeRouteEnter, side effects in afterEach.
Assign each concern to one stage across the app, so teams do not scatter overlapping checks through global, route and component guards.
## The full pipeline Vue Router 5 resolves every navigation through the same ordered steps. For an HR user leaving `/employees/7/edit` for a lazily loaded `/payroll` route whose record has a `beforeEnter`: 1. **Navigation triggered** by a RouterLink, `router.push()` or Back. 2. **Leave guards** in components being deactivated: the edit form's `beforeRouteLeave` option and its `onBeforeRouteLeave` guards, deepest record first. 3. **Global `beforeEach`** guards, in the order they were registered. 4. **Update guards** in reused components: `beforeRouteUpdate` and `onBeforeRouteUpdate` of records that stay matched (here, a shared layout if it has any). 5. **`beforeEnter`** of the records being entered, parent before child. 6. **Async route components resolved**: the payroll chunk downloads now. 7. **`beforeRouteEnter`** in the components being activated. 8. **Global `beforeResolve`** guards. 9. **Navigation confirmed**: the URL and `router.currentRoute` change. 10. **Global `afterEach`** hooks. 11. **DOM updates**. 12. **`next(vm)` callbacks** from `beforeRouteEnter` run with the mounted instances. Between steps the router checks whether a newer navigation has started; if so, this one is cancelled. And any guard that returns `false`, returns a location or throws ends the pipeline at that point. ## What each stage is good for | Stage | Typical use in the HR portal | |---|---| | leave guards | unsaved-changes confirmation on the edit form | | `beforeEach` | is anyone signed in; cheap checks before any chunk loads | | update guards | refetch when params change on a reused page | | `beforeEnter` | a rule for one route, e.g. payroll only during open periods | | `beforeRouteEnter` | component-level preconditions, Options API only | | `beforeResolve` | permission prompts or data you want only for pages that will render | | `afterEach` | page title, analytics, focus management | The ordering explains a few choices. Authentication belongs in `beforeEach` because it runs before step 6, so a signed-out user does not even download the payroll chunk. `beforeResolve` runs after everything else has agreed, so work placed there is not wasted on a navigation a later guard would reject. ## When `beforeEnter` does not run `beforeEnter` fires only when a record is **entered from a different route**: - not when only params, query or hash change on the same route, such as `/payroll?month=08` to `/payroll?month=09`; - not when moving between two children of the parent that carries it. It accepts a single function or an array of functions, run in order. For a rule that must re-run on every param change, use an update guard or a global guard reading `to.meta`. ## Nested records change the order within a step With nested routes, one navigation leaves, updates and enters several records at once. Suppose the edit form lives at `/hr/employees/7/edit` under an `/hr` layout record, and payroll is `/hr/payroll`: - the `/hr` layout stays matched, so its update guards run in step 4, even though its own params did not change; - the employee records are left, and their leave guards run deepest record first, so the form's guard answers before its parent's; - entering records run their `beforeEnter` from parent to child, so an `/hr` rule would run before a payroll rule if `/hr` were being entered. This is why a check on a parent record's `beforeEnter` does not re-run when moving between its children: the parent is updating, not entering. ## `beforeRouteEnter` and `next(vm)` `beforeRouteEnter` runs before the component instance exists, so it has no `this`. It is the only guard where passing a **callback** to `next` does something: the router stores it and calls it with the component instance once the view has mounted, at step 12. There is no Composition API version of `beforeRouteEnter`; in `<script setup>` the same work usually moves into `setup` itself or into a `beforeEnter`/`beforeResolve` guard. The `next` argument is deprecated in Vue Router 5, and a development warning fires whenever it is called, the callback form included. ## After the fact `afterEach` hooks receive `to`, `from` and a navigation failure if there was one, but they cannot cancel or redirect: the navigation is already settled. That makes them the place for side effects such as `document.title` from `to.meta.title`. ## Common mistakes - Expecting `beforeEach` to run before leave guards. - Putting an expensive fetch in `beforeEach`, where a later guard can still reject the navigation. - Relying on `beforeEnter` for checks that must repeat on param changes. - Trying to redirect from `afterEach`.
- Why does a signed-out user not download the payroll chunk when authentication lives in `beforeEach`?Lazy route components are resolved at step 6, after `beforeEach`, update guards and `beforeEnter`. A `beforeEach` that redirects to login ends this navigation before the router ever calls the payroll component's import function, so the chunk is never requested.
- What order do guards in a `beforeEnter` array run in, and what happens if the first one redirects?They run in array order, each as its own step in the queue. If the first returns a location or `false`, or throws, the pipeline stops there and the second never runs for that navigation; a redirect then starts a new navigation through all guards again.
Think of a building with checkpoints: the room you are leaving signs you out first, then the front desk checks everyone, then the corridor you stay in, then the door of the new room, and only when the room is unlocked and ready does a final supervisor sign off before you step in. Signing the visitor log happens after you are inside.
saying these in an interview costs you the question
- Global beforeEach guards run before the leaving component's leave guard
- beforeResolve runs after the navigation is confirmed
- beforeEnter runs again whenever the route's params change
- afterEach can redirect by returning a route location
- beforeRouteEnter can read this, like the other in-component guards