I’m working on setting up the Vue Router for my application, and I’ve encountered an issue with the history
mode. When I use this mode, the URL updates correctly according to my route definitions, but refreshing the page results in a 404 error. If I don’t use history
mode, the URL in the address bar doesn’t change as I navigate through my app.
I understand that to use history mode, certain server-side configurations are required. Upon reviewing the Nextcloud server’s source code, I noticed that it utilizes the history mode for Vue routing, suggesting that the server should already be configured to support this feature. However, I’m still facing the refresh issue and am unsure of how to proceed.
Still trying to figure out…
Hello.
You have two options here:
- Use the web hash history mode and be done
- Use the (HTML5) hash history mode and configure the server accordingly.
Hash history mode
The hash history mode uses a hash added to the address to store the routing. So, for example, in the cookbook app we use this mode. The URLs look like https://example.com/apps/cookbook/#/recipe/1234. This is the URL for the route /recipe/1234
inside the Vue component located at the main index document.
The drawback is that the part after the #
is not considered for SEO. So, as long as you are only using for internal routes, you are fine. Otherwise you should go to the web history mode.
Web history mode
When you activate web history mode, the corresponding address would be https://example.com/apps/cookbook/recipe/1234. Note that the browser does not know where the actual URL ends and where the routing inside the Vue component starts. Thus, a request is done to the actual URL as it is.
In order to cope with this, the backend needs fixing. The calendar app uses this mode. The corresponsing route defines /embed/:token/:view/:firstday
.
The backend code in PHP defines corresponding routes to catch all possible values as well. So, the backend would know the token, the view name and the time range to display when reloading. It is not used, however but just provided to allow for clear parsing the URL as the actual URL hitting the server would be https://example.com/app/calendar/token/2345/daily/now (or similar) for example.
It is no bad idea to provide this for your app as it allows for more stable URLs and does not rely on the hash anchor of links to work.
Christian
Here’s my Vue routers:
const router = new VueRouter({ mode: 'history', base: generateUrl('/apps/qlcv'), routes: [ { path: '/', component: UpcomingTasks, }, { name: 'work', path: '/work/:sharedWorkID', component: TaskList, }, ] })
And here’s my routes.php
return [ 'routes' => [ // Page ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'], // Work ['name' => 'Work#createWork', 'url' => '/create_work', 'verb' => 'POST'], ['name' => 'Work#getUsers', 'url' => '/users', 'verb' => 'GET'], ['name' => 'Work#getWork', 'url' => '/works', 'verb' => 'GET'], ['name' => 'Work#updateWork', 'url' => '/update_work/{work_id}', 'verb' => 'PUT'], ['name' => 'Work#deleteWork', 'url' => '/delete_work/{work_id}', 'verb' => 'DELETE'], ], ];
When I refresh the page, the path /work/:sharedWorkID
returns a 404 error. Do you mean I need to define a router for this path in routes.php
which accepts param sharedWorkID
?
Exactly.
As a route must be unique in the PHP part, you must provide a postfix
for one of the routes. That would be something like
['name' => 'page#index', 'url' => '/work/:shareWorkId', 'verb' => 'GET', 'postfix' => 'selectedWork'],
It might be a good advice to collect all API endpoints (like /create_work
etc) under a common prefix to reduce the risk of name clashes here (e.g. move to /api/create_work
). Then you must ensure, that no Vue route starts with the /api
prefix and all collisions are ruled out.
Christian