NProgress Integration in Vue-Element-Admin's Router beforeEach Guard: A Complete Guide
NProgress displays a slim progress bar during route navigation by starting in router.beforeEach and completing in router.afterEach inside src/permission.js.
Vue-Element-Admin implements a seamless loading state using NProgress to provide visual feedback while authentication checks and async route resolution occur. The integration lives entirely within the global navigation guards in src/permission.js, ensuring users see activity whenever the router is busy processing permissions or fetching user data.
How NProgress Works in the Router Guard
The implementation follows a strict lifecycle: start immediately on navigation intent, then resolve explicitly on redirects, errors, or successful completion.
Configuration and Initial Setup
The library is imported and configured at the top of src/permission.js to disable the default spinner and show only the thin top bar:
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css'
NProgress.configure({ showSpinner: false })
This configuration removes the spinning indicator (lines 4‑9), leaving a minimal progress bar that matches the admin dashboard’s clean aesthetic.
Starting the Progress Bar
Every navigation request triggers NProgress.start() inside the router.beforeEach guard before any async logic executes:
router.beforeEach(async(to, from, next) => {
NProgress.start()
// Token validation and permission checks follow...
})
Located at lines 13‑16, this ensures the bar appears instantly when a user clicks a link, even while the app fetches user info or generates accessible routes.
Handling Redirects and Error States
The guard manually calls NProgress.done() in three specific scenarios to prevent the bar from hanging when navigation is aborted:
Redirecting authenticated users from login:
When a logged-in user attempts to access /login, the guard redirects to / and immediately clears the bar (lines 24‑28):
if (to.path === '/login') {
next({ path: '/' })
NProgress.done() // hack: https://github.com/PanJiaChen/vue-element-admin/pull/2938
}
Handling authentication failures:
If store.dispatch('user/getInfo') throws an error, the guard catches it, displays a message, redirects to login, and clears the progress bar (lines 48‑54):
Message.error(error || 'Has Error')
next(`/login?redirect=${to.path}`)
NProgress.done()
Blocking unauthenticated access: For users without a valid token accessing protected routes, the guard redirects to login and completes the progress (lines 63‑66):
next(`/login?redirect=${to.path}`)
NProgress.done()
Completing Successful Navigation
The final safety net resides in router.afterEach, which guarantees the bar disappears once navigation finishes, covering cases where the beforeEach guard did not manually call done() (lines 71‑74):
router.afterEach(() => {
NProgress.done()
})
Practical Implementation Examples
Minimal Standalone Guard
To replicate the Vue-Element-Admin pattern in any Vue Router project:
// router/guard.js
import router from './index'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
NProgress.configure({ showSpinner: false })
router.beforeEach((_to, _from, next) => {
NProgress.start()
next()
})
router.afterEach(() => {
NProgress.done()
})
Custom Async Guard with Error Handling
When implementing complex permission checks, wrap async logic and ensure done() fires in the finally block:
router.beforeEach(async (to, from, next) => {
NProgress.start()
try {
await fetchPermissions(to.meta.requiredRoles)
next()
} catch (e) {
next('/error')
} finally {
NProgress.done()
}
})
The Redirect Hack Explained
When redirecting inside beforeEach, always call NProgress.done() before or immediately after next() to avoid the bar lingering due to the aborted navigation:
if (to.path === '/login' && hasToken()) {
NProgress.done()
next({ path: '/' })
}
This pattern prevents the progress bar from freezing at 90% when the router interrupts the current navigation to perform a redirect.
Summary
- File location: All NProgress logic resides in
src/permission.js, lines 4‑74. - Lifecycle:
NProgress.start()fires inrouter.beforeEach;NProgress.done()fires manually on redirects/errors and automatically inrouter.afterEach. - Configuration: The spinner is disabled via
NProgress.configure({ showSpinner: false })to show only the top progress bar. - Error resilience: Manual
done()calls in catch blocks and redirect paths ensure the UI never remains stuck in a loading state.
Frequently Asked Questions
Where is the NProgress logic located in Vue-Element-Admin?
The NProgress integration is implemented entirely within src/permission.js. This file registers the global router.beforeEach and router.afterEach hooks that control the progress bar lifecycle alongside authentication checks.
Why is NProgress.done() called before next() on redirects?
Calling NProgress.done() before next() on redirects prevents the progress bar from hanging. When next({ path: '/' }) interrupts the current navigation, the router.afterEach hook may not fire immediately, so manually completing the progress ensures the bar clears before the new route resolves.
How do I customize the NProgress appearance in Vue-Element-Admin?
Modify the configuration object in src/permission.js (lines 6‑9). For example, enable the spinner and adjust animation speed:
NProgress.configure({ showSpinner: true, speed: 400, trickleSpeed: 200 })
You can also override CSS classes defined in nprogress/nprogress.css to change the bar color or height.
Does NProgress work with async route guards?
Yes. The Vue-Element-Admin implementation specifically uses async/await inside router.beforeEach to fetch user information and permission routes. NProgress.start() runs immediately, providing visual feedback during the entire async resolution period until done() is called explicitly or via router.afterEach.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →