Understanding SPA Router: Hash vs History Mode and Server Configuration
This article explains how single‑page applications use router mechanisms, compares hash and history routing modes, and demonstrates the required server‑side (Node) and Nginx configurations to make history mode work without page reloads, including code examples and best‑practice tips.
SPA (single‑page application) loads all HTML, JavaScript, and CSS in a single page and changes the view without requesting the server when the route changes.
Two ways to implement SPA routing:
Hash mode – works in older browsers (IE8+); changes the URL fragment after # and listens to the hashchange event, which does not trigger a page reload.
History mode – supported from IE10 onward; uses the History API’s pushState and replaceState methods together with the popstate event to modify the URL without a server request.
Tip: you can check browser support for these features at https://caniuse.com .
Server support for history mode
History mode requires server‑side configuration so that unknown URLs are redirected to the SPA entry point. Below are two verification setups.
Node server verification
Prepare a Vue project, build it, and create a simple Node server:
const path = require('path')
const express = require('express')
const history = require('connect-history-api-fallback')
const app = express()
app.use(history()) // enable history mode compatibility
app.use(express.static(path.join(__dirname, './dist')))
app.listen(3003, () => {
console.log('server open')
})Steps:
Run node server.js to start the server.
Open http://localhost:3003 and navigate to a route (e.g., /about ).
Refresh the page – it loads correctly.
Remove the app.use(history()) line, restart the server, and refresh the same route – the page fails to load.
Conclusion: History mode needs server‑side compatibility.
Nginx verification
Place the built dist folder in the Nginx directory and configure Nginx as follows:
server {
server_name localhost;
listen 3000;
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location / {
root /usr/local/etc/nginx/dist;
index index.html index.htm;
# try_files $uri $uri/ /index.html;
}
}Steps:
Start Nginx.
Visit http://localhost:3000 and navigate to a route (e.g., /about ).
Refresh – the page does not load.
Uncomment the try_files $uri $uri/ /index.html; line, reload Nginx, and refresh again – the page loads correctly.
Conclusion: History mode also requires proper Nginx configuration.
Overall conclusion : When using history routing in a SPA, you must configure the backend (Node, Nginx, etc.) to serve the entry HTML for unknown paths, a step often overlooked by front‑end developers.
Other router topics
Lazy‑load routes to reduce bundle size; ensure Babel plugins are configured if lazy loading fails (see https://router.vuejs.org/zh/guide/advanced/lazy-loading.html ).
Dynamic routes can pass parameters via props: true to avoid relying on route‑based props.
import Vue from 'vue'
import App from './App.vue'
import router from 'vue-router'
import index from './index.vue'
Vue.use(router)
const routes = [
{
path: '/',
name: 'index',
component: index
},{
path: '/about',
name: 'about',
component: () => import('./about.vue') // lazy load
},{
path: '/hello/:id', // dynamic route
props: true, // enable props passing
name: 'hello',
component: () => import('./hello.vue')
}
]
new Vue({
router: new router({routes, mode: 'history'}),
render: h => h(App),
}).$mount('#app')New Oriental Technology
Practical internet development experience, tech sharing, knowledge consolidation, and forward-thinking insights.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.