I create 404 pages as a standard practice in my Vue applications. You need that to manage browser page refreshes and to serve direct URLs for all possible pages in your application.
Vue app has two parts -
- backend API
- frontend routes (pages)
Any and all requests to the server go through our Nginx web server. Nginx will show ‘404: page cannot be found’ error if we try to access any page that does not exist for the webserver.
The pages (or views) in a Vue application are known to Vue, but do not exist as static pages for the web server to cater to specific routes.
For e.g. we will not find a “myapp.html” in the public folder to display https://myapp.com/myapp. Since Nginx does not find “myapp” and it cannot really know that it has to automatically pass control to Vue, a ‘page not found’ error is only apt from its perspective.
Only Vue knows what to do with such specific page requests. For Vue to know such a thing, the request has to reach index.html / main.js from where Vue takes over.
Do remember though, it will work perfectly fine if you go to https://myapp.com and click on a link that points to <router-link to="/myapp">My App</router-link>
. But refreshing that page (in the browser) or directly entering that link in browser will not work.
Since our application will also likely have Vue router and history enabled, this problem will be compounded when user tries accessing specific pages from history.
To enable Nginx to manage specific URIs, we need to force Nginx to route all requests to Vue - this implies trying the URL or passing request to our index.html. We will do exactly that by changing nginx.conf
to handle both back-end requests ("/api/*") and front-end URI requests.
# redirect https://myapp.com/api/user to `user` resource at backend
location /api/ {
proxy_pass http://localhost:3333;
proxy_set_header Host $host;
}
# redirect all requests to specific pages of frontend
location / {
try_files $uri $uri/ /index.html;
}
So, what happens if you now access a page that does not exist even within Vue? The page can be simply redirected to our index.html. This may be a bad user experience.
We use a 404 page in our application to avoid the above scenario.
-
First, create a 404 page as a view (the below example uses Vuetify).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
<!-- views/NotFound.vue --> <template> <div class="NotFound"> <v-container> <v-layout row wrap> <v-flex xs12> <v-card height="400" color="transparent" flat> <div class="display-3 mt-5">Page not found.</div> <div class="grey--text lighten-5"> The page you are trying to get to never existed in this reality, or has migrated to a parallel universe. </div> <div class="paragraph-text mt-2"> <br /> <br />Try going back to home page and repeating your action. Or, contact helpdesk for support. </div> </v-card> </v-flex> </v-layout> </v-container> </div> </template> <style> .paragraph-text { font-size: 18px; } </style>
-
Next: change router to include a page that is the mother of all pages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
// router.js import Vue from "vue"; import Router from "vue-router"; import Home from "./views/Home.vue"; import store from "./store/index"; Vue.use(Router); xport default new Router({ mode: process.env.CORDOVA_PLATFORM ? "hash" : "history", base: process.env.BASE_URL, routes: [ { path: "/", name: "home", component: Home, beforeEnter: dynamicHome }, { path: "/user", name: "user", component: () => import("./views/User.vue") }, { // catch all 404 - define at the very end path: "*", component: () => import("./views/NotFound.vue") } ] });
Using this arrangement, you have achieved three things -
- All server requests are passed to Vue due to the configuration in nginx.conf (or equivalent)
- Vue expects all requests to be sent to the router. All valid pages are managed as expected
- If any page is not found, Vue will show the custom 404 page