Vue direct URL is not working, only router-link click - vue.js

This may be a known Vue routing thing that I am totally missing.
So I have a .vue file that uses the url /hardware.
Here is the routing
{
path: "/hardware",
name: "Hardware",
component: () =>
import(/* webpackChunkName: "hardware" */ "../views/Hardware.vue")
},
Going to /hardware directly using a link on an external site or typing it in the address bar does not work, gives me Page Not Found.
But clicking on this link in my nav bar does work.
<router-link to="/hardware">Hardware</router-link>
Am I missing something super obvious that I missed when I was learning routing? Is this because it is a single page application? Thanks in advance for any help.
Adding that I do have history mode on, wondering if this is the issue?
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes
});

Following back from comments to answer (Netlify) Vue-router works locally and not at the hosting/deployment side like Apache/Nginx/Firebase Hosting as:
1)
Pretty-URL / Hashbang dilemma in SPA.
The server needs to redirect when your Vue project enabled history mode. in apache, just some redirect rules needed to be done via .htaccess similarly, so as most of the hosting services included Netlify (you need to check the routes redirect rules at Netlify there). As server page not found, telling us that your route doesn't have actual files under that specified /route at their side.
Previous thread: Vue Router return 404 when revisit to the url
2) If your project for Multi-page-mode instead of going hashbang SPA, Your Vue Project needed to be configured little bit further: Either via SSR or pre-rendering static files before deployment

It could be that your browser is adding a trailing slash to giving you "/hardware/" which does not match your route. In the past, I had created an alias to match both routes such as "/hardware" and "/hardware/".

I faced the same issue nowadays and decided to share my thoughts with the community.
You can easily resolve the bug just by removing mode: "history" from the Router. Then it will be automatically replaced by the hash (#) in your URLs. It's going to work then even if you'll use a direct link in the browser.
However, based on the latest SEO recommendations History mode is more preferable because URLs without # are better tracked by Google.
If you would like to save History mode, you need to enable history mode on your server. I use Express middleware and the solution in my case is next:
const express = require('express');
const history = require('connect-history-api-fallback');
const app = express();
app.use(history());
app.use(express.static('src'));
app.get('/', (req, res) => {
res.sendFile('src/index.html');
});
app.listen(3000, () => console.log('server started'));

Related

I cant seem to remove the # symbol from website

my website is https://jaylanthedev.com/#/ but for some reason it needs to # sign to get to any other page that is not the homepage. I am very confused as to why this is. It is a vue app hosted on azure and after googling I am not able to get very far with this. Also not sure if this is a vue problem or a azure problem. Anyone have any ideas?
Ex:
Works: https://jaylanthedev.com/#/about
Does not work: https://jaylanthedev.com/about
If you read here:
https://router.vuejs.org/guide/essentials/history-mode.html#example-server-configurations
The default mode for vue-router is hash mode - it uses the URL hash to
simulate a full URL so that the page won't be reloaded when the URL
changes.
So Vue has a default hash to load its routes.
To switch to history mode:
const router = new VueRouter({
mode: 'history',
routes: routes
})
But - this means that you need a server to render your pages. You need to have your client be running on a node server like express or anything similar so it can route the pages without re-rendering.

Returned data being rendered instead of page structure in Nuxt

I'm trying to return data as JSON from the express server for a route. The data returns fine but when i open the NUXT page on the browser than the JSON data gets outputted instead of the page HTML.
Note the express route is the same as the page route. I know the routes are conflicting with each other. Do i need to have the server and front-end on different ports? Is there anything wrong i'm doing here?
Thanks
To avoid conflicts such as that you should use a prefix like /api/ or /api/v1/ something like that
In nuxt.config.js you need to define your server middleware
serverMiddleware: ["~/api/index.js"]
That file is your server. At the bottom you need to export it like this:
module.exports = {
path: "/api",
handler: app
}
Note here: app is your express app if you use express.js.
This here: const app = express();
If everything worked your root of your API should be available under host:port/api/
you cant do this if the routes for backend and frontend exactly same. this is route rules that they have to be unique and its not backend or frontend issue for e.x. you can have two routes with same url in express(api), nuxt too.
if we say the application for example is post office, the route are path to a house address (controller or action) so we can have two path to get the a house but its confusion have a same path(url or route) and different houses.
simple solutions:
as you said make the api and front separate with different ports or different domains or even have a prefix for your express routes
in express handle all of them, means return view or page with data needed instead of json data

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

Nuxt generate is keeping my dynamic routes working

I am using nuxt for a static webapp, using "mode: spa" and "nuxt generate".
The docs say that dynamic routes do not work with this, but my app (/dist) still works on static server after generating, even though the routes aren't generated. I cant figure out why.
Before generating, my routes look like:
export function createRouter () {
return new Router({
mode: 'history',
base: '/',
routes: [
{
path: "/",
component: _36d3a217,
name: "index"
},
{
path: "/:focus",
component: _fbe76838,
children: [
{
path: "",
component: _6d415767,
name: "focus"
},
{
path: ":view",
component: _19cdee48,
name: "focus-view"
}
]
}
],
fallback: false
})
}
Now, the generated /dist does not create the /focus directory as expected...But In my app, I am using route URL params to query an API and it still works.
ie a route like below, the component will use "thisFocus" and "thisView" as parameters in the API:
/thisFocus/thisView
Since the dynamic routes do not exist in /dist, i would think that this would not work anymore. So how does the app still use those URL params successfully without the routes existing?
Edit: another more simple way to ask maybe: why can i still access /:focus/:view route.params even though the routes dont exist?
If you use nuxt generate, you usually want a statically generated page. That means, having one HTML file per route which contains actual HTML which was rendered by the server.
You want that because it'll give you the "best of both worlds", good SEO, faster TTI and so on but without running a Node.js server all the time. (Further read)
If you want a traditional SPA, you typically have just one index.html file with almost no HTML but Javascript included.
Source code of a typical SPA
Dynamic routes
When you "pre-render" (=== statically generate) your page, Nuxt needs the information which routes it should render. For routes without parameters that's easy (e.g. about.vue or posts/index.vue). As soon as there are dynamic parameters, Nuxt can't "guess" them.
So yes, dynamic routes are "ignored" because Nuxt don't know what do to with them except you tell Nuxt which routes to pre-render.
These routes will then be generated. This does not mean that you can't access dynamic routes that you didn't provide to Nuxt. You can still access them (example: a post that doesn't exists) and the requests will be parsed (depending on your server config and whether you have generate.fallback enabled or not) but you lose the SEO benefit and see a spinner as the fallback file is equivalent to the index.html from your traditional SPA.
Source: Replied on github by manniL who is a nuxt core member

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