The following url:
http://www.exemple.com/agency/
is NOT the same as the following url:
http://www.exemple.com/agency
for SEO crawler and HTTP point of vue.
This is not a big deal for a SPA without SEO requirement but in an SSR app this is critical.
If I use, for example, Express.js to serve my application with the strict mode and following routes :
app.set("strict routing", true);
app.get('/agency/', agencyPage);
app.get('/*', errorPage);
The pages (based on Vue renderer) HTTP served for following URL will be :
http://www.exemple.com/agency/ ==> agencyhttp://www.exemple.com/agency ==> errorhttp://www.exemple.com/foo ==> errorBut, when client-side Vue will perform hydratation, the component/route will be resolved as following
http://www.exemple.com/agency/ ==> agency : Goodhttp://www.exemple.com/agency ==> agency : Failhttp://www.exemple.com/foo ==> error : GoodFor http://www.exemple.com/agency, hydratation fail because the source code come currently from errorPage process (/agency/ is not the same page as /agency and HTTP returned a 404 error code) but client-side Vue Router find a route /agency for /agency/.
There is maybe a way to explain to router how the route should be match ?
declare type RouteConfig = {
...
strict?: boolean
...
}
Allows Vue Router to work in the same way as usual but allows to corretly recognise HTTP different url for SEO/SSR mode with 'strict mode'.
My current workarround is to check the following before use Vue Proccess client-side :
if (window.location.pathname.slice(-1) !== '/') {
window.location = window.location.pathname + '/';
}
but that not allows usage of url not ended by '/' so a « strict mode » should be the true solution.
This will be possible once the pr #1215 gets merged by passing setting strict: true on the pathToRegexOptions property of a route
However, from a user point of view, foo/ and foo are the same, so I'd recommend you to handle the case in your server, there's probably an option for express. Out of curiosity, why do you need to make that difference?
Thx @posva !
Just because it's not the same route for crawler.
http://www.test.com/bonjour (file bonjour under directory /)
http://www.test.com/bonjour/ (file « index (for example) » under directory /bonjour/)
So for SEO, it's important when crawler pass on http://www.test.com/bonjour and http://www.test.com/bonjour/ which this two url are not « duplicated content ». So I let my server respond one not exist and other exist.
And you are right, some user don't do the difference, and ultimatly for a pure front-side user experience it's a better thing to not have different pages behind /bonjour and /bonjour/ so the most common case is just to return 404 from one of two URL OR a 301 redirect from one to other.
Vue Router actually not allows that. I wanted to force « /bonjour » to be « /bonjour/ » with redirect but without success too :/
EDIT : I will provided some full SEO/SSR website with Vue and NodeAtlas (based on Express) with isomorphisme and it's really important my front can be display error page from /bonjour and real page from /bonjour/ to allows hydratation to be performed because server serve error in one case and real page in others.
I will probably directly do a 301 for all non slash-ended route to slash-ended and let « front » part not do difference between two type of URL, maybe.
This got merged at #1215
You'll have to provide an option to the route definition:
pathToRegexOptions: { strict: true }
(it's not released yet though)
Vue guys! You're bests!
EDIT:
(it's not released yet though)
I will wait a little more ;)
Re @posva
As I already said here (after cloture of point): https://github.com/vuejs/vue-router/issues/1215
This do not resolve my point, I wonder myself it's there is an issue...
If I set pathToRegexpOptions: { strict: true }, only page « without » trailing work. And I expected page only « with » that's work...
To resume, if I create:
/ and /test/ for exemple
/ <= OK
/test/ <= OK
/test <= NOK
and with vue-router, this is do.
/ <= OK
/test/ <= OK
/test <= OK
With usage of pathToRegexpOptions: { strict: true } I expected this following your advices
/ <= OK
/test/ <= OK
/test <= NOK
But what I have is that
/ <= OK
/test/ <= NOK
/test <= OK
So it's not normal? That is the reverse of description of strict no?
It's possible to re-open this issue and help to resolve that in anyway ?
@Haeresis I went a bit too fast creating the issue, it works as it should: http://jsfiddle.net/0evuj9fs/
Thx a lot @posva for your help.
Your « simple » case work, indeed but... let me introduce this:
I have just add a new entry error with /* to match all others pages. This is the minimal for a page that doesn't exist.
I also set /home/ and not /home because it's the case I want it match, but if you kept (/home) that change nothing.
See the behavior of link, it's change in fonction of source target!
Follow this cases:
So when you start running, it is display: Error (I expected Home)
/home and you will see Home (OK)/foo and you will see Foo (I expected Error)/foo/ and you will see Foo (OK)/error and you will see Error (OK)/plop and you will see Error (OK)/hoho and you will see Error (OK)/foo/ and you will see Error (WTF ! Previously it was OK...)/foo and you will see Error (Error Great ! But Previously it was Foo...)/home and you will see Home (OK)/foo/ and you will see Error (WTF ! Again...)/foo and you will see Error (WTF ! Again...)/home and you will see Home (OK)/foo and you will see Foo (WTF ! Power!)/foo/ and you will see Foo (My brain will exploding!!!)Vue... Vue... What you can do to me T-T
It is the same thing I have with hydratation, after my server response the true response.
Now remove , pathToRegexpOptions: { strict: true }, and ok, /foo and /foo/ are the same page, but all work as expected. (and the default page is Home, not Error).
Where is something I don't understand ?
:D that smells like an issue then !
I had the same problem. This is a workaround I found. With the @nuxtjs/sitemap module everything is ok.
extendRoutes: (routesIn) => {
routesIn.forEach((r) => {
if (r.path.includes('/blog')) {
r.path = r.path.replace('/blog', '/blog/');
}
});
return routesIn;
}
Most helpful comment
This got merged at #1215
You'll have to provide an option to the route definition:
(it's not released yet though)