Skip to content

Differentiate slash-ended routes (foo and foo/) #1443

@MachinisteWeb

Description

@MachinisteWeb
Contributor

What problem does this feature solve?

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/ ==> agency
  • http://www.exemple.com/agency ==> error
  • http://www.exemple.com/foo ==> error

But, when client-side Vue will perform hydratation, the component/route will be resolved as following

  • http://www.exemple.com/agency/ ==> agency : Good
  • http://www.exemple.com/agency ==> agency : Fail
  • http://www.exemple.com/foo ==> error : Good

For 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 ?

What does the proposed API look like?

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'.

Activity

MachinisteWeb

MachinisteWeb commented on May 20, 2017

@MachinisteWeb
ContributorAuthor

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.

changed the title [-]Feature Request: Vue Router Strict Mode[/-] [+]Differentiate slash-ended routes (foo and foo/)[/+] on May 20, 2017
posva

posva commented on May 20, 2017

@posva
Member

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?

MachinisteWeb

MachinisteWeb commented on May 20, 2017

@MachinisteWeb
ContributorAuthor

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.

posva

posva commented on Jun 16, 2017

@posva
Member

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)

MachinisteWeb

MachinisteWeb commented on Jun 16, 2017

@MachinisteWeb
ContributorAuthor

Vue guys! You're bests!

EDIT:

(it's not released yet though)

I will wait a little more ;)

MachinisteWeb

MachinisteWeb commented on Jun 30, 2017

@MachinisteWeb
ContributorAuthor

Re @posva

As I already said here (after cloture of point): #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 ?

posva

posva commented on Jun 30, 2017

@posva
Member

@haeresis I went a bit too fast creating the issue, it works as it should: http://jsfiddle.net/0evuj9fs/

MachinisteWeb

MachinisteWeb commented on Jul 1, 2017

@MachinisteWeb
ContributorAuthor

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)

  • After, click on /home and you will see Home (OK)
  • After, click on /foo and you will see Foo (I expected Error)
  • After, click on /foo/ and you will see Foo (OK)
  • After, click on /error and you will see Error (OK)
  • After, click on /plop and you will see Error (OK)
  • After, click on /hoho and you will see Error (OK)
  • After, click on /foo/ and you will see Error (WTF ! Previously it was OK...)
  • After, click on /foo and you will see Error (Error Great ! But Previously it was Foo...)
  • After, click on /home and you will see Home (OK)
  • After, click on /foo/ and you will see Error (WTF ! Again...)
  • After, click on /foo and you will see Error (WTF ! Again...)
  • After, click on /home and you will see Home (OK)
  • After, click on /foo and you will see Foo (WTF ! Power!)
  • After, click on /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 !

giticon

giticon commented on Oct 22, 2020

@giticon

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;
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @posva@MachinisteWeb@giticon

        Issue actions

          Differentiate slash-ended routes (foo and foo/) · Issue #1443 · vuejs/vue-router