How to bypass router for certain URLs with Vue Router? - vue.js

I'm using Vue Router with Vue 3 in a web application I'm working on, and have a 'catch all' route defined as the last route:
{
path: "/:catchAll(.*)*",
component: () => import("pages/Error404.vue")
},
This is picking up everything, though, including calls to the /api/ back end (although not via Ajax), and even things like '/test.csv', which is a link to a CSV file in the root directory.
How can I bypass the router for certain URLs, allowing them to be treated as regular requests?
Incidentally, I don't know whether this is relevant, but the application in question is a PWA built using Quasar. When I make the call to e.g '/test.csv', I see a request for 'service-worker.js' with a 304 response code in my nginx access log, confirming that the request is being handled by the router rather than nginx.

Related

Allow API routes in Vue Router?

I'm working on a Vue 3 app (using Quasar) with Vue Router. I want the user to be able to click on certain links (with paths beginning '/api/') which bypass the router completely and go straight to the backend API. But everything is getting picked up instead by the catch-all route (path: "/:catchAll(.*)*"). I tried adding a route without a matching component, path: "/api/*", but that doesn't work.
Is there a way for me to tell the router to ignore certain paths and let them be handled by the server?

How to pass runtime environment variables to client side in NuxtJS SSR application

My NuxtJS applications makes HTTP request to a backend API. I am using nuxtjs/axios pluging to make these requests. I have configured base URL for API in nuxt.config.js like below
axios: {
baseURL: process.env.BASE_URL,
},
In Local, I have a .env like below
BASE_URL=http://localhost:8080
On AWS ECS Container, I have declared environment variable with
Key: BASE_URL and Value: https://example.com
On running the application following happens
When application is server-side rendered, base URL for API is resolved correctly e.g https://example.com/previews
When application is client-side rendered, base URL for API is not resolved to https://example.com but rather to the same IP address that my web application is accessible on.
So, what I understand might be happening is, that the process.env.BASE_URL is not getting passed from the server-side(NodeJS server) to client-side(Web Browser). Hence it is falling back to the application's IP address.
Any idea why such a behavior and how to pass the environment variable to client-side as well? Or what might be causing this.
Thanks.

Error 404 on a page that exists and that works fine through internal link

I created a website with several pages on Vue.js.
Everything is working fine locally, but when I deploy to Heroku, all pages are only working when I click on an internal link in my menu that redirects to the corresponding page (using router push).
When I try to access directly /any-page from the browser I get a 404 with a message saying "Cannot GET /any-page" whereas the same page is displayed correctly via a click on a link.
As I mentioned when I locally serve my app I don't have this problem.
I really can't see where this can come from, thanks in advance for your help.
There's a deployment guide specifically for Heroku in the official Vue CLI documentation.
You'll quickly notice the relevant information:
static.json
{
"root": "dist",
"clean_urls": true,
"routes": {
"/**": "index.html"
}
}
For SPA's (Single Page Applications), you'll want to point every route to the index. Vue router will take care of navigating to the proper page.
Heroku is serving the contents of your Vue build folder. Since Vue builds the app as a single index.html file, only the main route works.
Vue doesn't actually navigate to the route, it rather rewrites the the browser url using the history API and handles the loading of the new route.
You could use one of these options:
OPTION 1
You could use mode: "hash" to fix routes when reloading the page. However this will add a # before every route.
const router = new VueRouter({
mode: "hash",
routes: [...]
})
OPTION 2
Write an Node.JS (eg Express) app that routes every request to your index.html file. This is called a middleware
Reference: https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations

Laravel's intended() with vue router

I am working on a project and am struggling with redirecting to intended location after login.
The problem is that Laravel does not include Vues route (anything after #/...) so it always redirects me only to 'domain.com/'
I am using laravel routing only for 'login' 'logout' and '/' and rest of the app is single page utilizing vue routing.
Users of the app are receiving notification emails when they need to take action. Those email contain links to requests where their action is required (e.g. domain.com/#/request/3413). Of course they need to login to be able to access that so they are redirected to login page by laravel (domain.com/login#/request/3413)
After successful login I am trying to redirect them with
return redirect()->intended('/');
But it redirects them to 'domain.com/' instead of 'domain.com/#/request/3413'
Is there any way to make laravel include vues route in that redirect?
Thanks a lot!
So after some excruciating research I have found out that anything after # is handled by browser meaning that server does not see it so you cant access it in your PHP code. I found out thanks to this thread: Getting FULL URL with #tag
I am unsure if that part of the request is not even sent to server but it seems like that and is even pretty logical to me that it would be so.
So to solve this I changed the link sent to user via email to something like this
domain.com/?request=3413
This way I can access it in my PHP code and put together the redirect link after successfull login.
You can remove the # in the URL in Vue Router by enabling History Mode like so:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
You will need to direct all your requests to where you app lives. If your backend is Laravel, you can define a catch-all route in your routes/web.php file
Route::get('/{any}', 'SpaController#index')->where('any', '.*');
The caveat to this is that the server will no longer return 404s for paths that are not found so you will have to create a NotFoundComponent to display on your Vue app if a path is not found.
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
Read the Vue Router History Mode Documentation for more info

Vanity urls for files in Vue 2.1

Reading through the Vue Router docs this seems like it should be pretty simply, but I can't get it to work.
First I tried to use the file in S3
{
path: '/rules',
redirect: 'https://s3.amazonaws.com/itsclarke/vue-project/pdfs/rules.pdf'
}
This resulted in the redirect being appended to localhost:8080/#, so I got localhost:8080/#/https://s3.amazonaws.com/...
Also tried using the same approach with the static folder:
{
path: '/rules',
redirect: '../../static/rules.pdf'
}
This kept the path relative, but inestead of showing the pdf, it took me to localhost:8080/#/static/rules.pdf which isn't the path. localhost:8080/static/rules.pdf is what I need. This needs to use hash mode as well.
Using alias mode isn't much help either because I don't have components for these files. I know these redirects can be down on the server level, but I want to do it within Vue Router.
I don't think this is possible out of the box with vue-router - it expects the redirect value to be another client-side route, not a server-side url. I think your best bet would be to use a beforeEnter guard on your /rules route to redirect (using window.location) to the url. Alternatively, you could have your /rules route return a component that displays the pdf in an iframe.