Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(builder, router): enforce uniform trailing slash handling #6331

Merged
merged 8 commits into from
Sep 1, 2019

Conversation

manniL
Copy link
Member

@manniL manniL commented Aug 29, 2019

Types of changes

  • Bug fix (a non-breaking change which fixes an issue)
  • New feature (a non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Description

Trailing slash handling is important when it comes to SEO. For every existing Nuxt application, the content provided by /route and /route/ should be the same (opposed to how it sometimes worked back in the days). But when it comes to how the search engine sees our page, we have to be consistent and choose one of the options, either with or without a trailing slash.

Be consistent with the preferred version. Use it in your internal links. If you have a Sitemap, include the preferred version (and don’t include the duplicate URL).

With the current setup, it is not entirely possible to enforce trailing slashes (or the removal of them) without substantial effort.

As long as you have simple and fixed URLs, you can always append the slash (or not), but when it comes to resolved named routes (e.g. when using https://github.com/nuxt-community/nuxt-i18n/ ), things become difficult and hard to manage.

Thus, this PR


It introduces a new router option called trailingSlashes set to undefined by default. If it's set to true, trailing slashes will be appended on every route. If set to false, they'll be removed.

Therefore, we use the pathToRegexpOptions settings (per route) provided via vue-router (see vuejs/vue-router#1753 and vuejs/vue-router#1443)


This option should not be taken lightly and has to be tested thoroughly. When setting router.trailingSlashes to something else than undefined, one of the options (either with or w/o trailing slash) will stop working. 301 redirects should be in place before.


Related work:

#3448
#5746

TODO

  • check edge cases
    • index route
    • nuxt child routes
    • (???)
  • docs

Checklist:

  • My change requires a change to the documentation.
  • I have updated the documentation accordingly. (PR: #)
  • I have added tests to cover my changes (if not applicable, please state why)
  • All new and existing tests are passing.

@codecov-io
Copy link

codecov-io commented Aug 29, 2019

Codecov Report

Merging #6331 into dev will increase coverage by <.01%.
The diff coverage is 100%.

Impacted file tree graph

@@           Coverage Diff            @@
##             dev   #6331      +/-   ##
========================================
+ Coverage   95.7%   95.7%   +<.01%     
========================================
  Files         79      79              
  Lines       2652    2656       +4     
  Branches     683     685       +2     
========================================
+ Hits        2538    2542       +4     
  Misses        98      98              
  Partials      16      16
Flag Coverage Δ
#e2e 100% <ø> (ø) ⬆️
#fixtures 50.56% <50%> (-0.01%) ⬇️
#unit 92.35% <100%> (+0.04%) ⬆️
Impacted Files Coverage Δ
packages/config/src/config/router.js 100% <ø> (ø) ⬆️
packages/utils/src/route.js 100% <100%> (ø) ⬆️
packages/builder/src/builder.js 99.62% <100%> (ø) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e9c4bcf...1125ba4. Read the comment docs.

galvez
galvez previously approved these changes Aug 29, 2019
Copy link

@galvez galvez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea.

@pimlie
Copy link

pimlie commented Aug 29, 2019

Nice timing, have been struggling with trailing slashes in nuxt/press a bit the last weeks!

I'd recommend to include a util method so users can easliy normalize paths they use in their project as well, see eg here for the methods currently used in nuxt/press (but they could be improved on probably).

@atinux
Copy link
Member

atinux commented Aug 29, 2019

Good call!
Shouldn’t be easier to directly add a meta canonical directly so we fix the duplicate for SEO? (This is what we use for nuxtjs.org)

@manniL
Copy link
Member Author

manniL commented Aug 29, 2019

Shouldn’t be easier to directly add a meta canonical directly so we fix the duplicate for SEO? (This is what we use for nuxtjs.org)

@atinux

Well, canonical is one thing and easily realizable via layouts (example). But the internal link structure should reflect trailing slashes (or none) as well

@manniL
Copy link
Member Author

manniL commented Aug 29, 2019

I'd recommend to include a util method so users can easliy normalize paths they use in their project as well

@pimlie

What would be the use case when all (named) routes or those resolved programmatically will go in line with the config and fixed routes would be easy to change by appending/removing the /?

@pimlie
Copy link

pimlie commented Aug 30, 2019

@atinux Isnt that technically more a workaround then a fix? Due to the nature of a SPA the path resolve behaviour is just different then serving static files with a webserver (ie apache/nginx). How close do we want to stay to that 'original' behaviour?

@manniL If your router config lists all routes with a trailing slash, then your nuxt/router-links should point to a link with a trailing slash as well right?

Copy link
Member

@pi0 pi0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice improvement 👍

packages/utils/src/route.js Outdated Show resolved Hide resolved
route.path = route.path.endsWith('/') ? route.path : `${route.path}/`
}

if (trailingSlashes === false) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can make at an else if? This would save branch check-in cases that trailingSlashes is true + makes it more readable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about ?

if(trailingSlashes !== undefined) {
  const trailing = trailingSlashes ? '/' : ''
  route.path = route.path.replace(/\/+$/, '') + trailing
}

@@ -136,7 +136,8 @@ export const createRoutes = function createRoutes ({
srcDir,
pagesDir = '',
routeNameSplitter = '-',
supportedExtensions = ['vue', 'js']
supportedExtensions = ['vue', 'js'],
trailingSlashes = undefined
}) {
const routes = []
files.forEach((file) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not related to this PR) what do you think of refactoring forEach to ES6 for of? OR using files.map to directly assign the result of routes instead of pushing to the end.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plus one for using map instead ☺️

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do this later and not blocking this PR :)

packages/utils/src/route.js Outdated Show resolved Hide resolved
packages/config/src/config/router.js Outdated Show resolved Hide resolved
packages/utils/src/route.js Outdated Show resolved Hide resolved
route.path = route.path.endsWith('/') ? route.path : `${route.path}/`
}

if (trailingSlashes === false) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about ?

if(trailingSlashes !== undefined) {
  const trailing = trailingSlashes ? '/' : ''
  route.path = route.path.replace(/\/+$/, '') + trailing
}

@manniL
Copy link
Member Author

manniL commented Aug 30, 2019

If your router config lists all routes with a trailing slash, then your nuxt/router-links should point to a link with a trailing slash as well right?

Correct. If you use fixed URLs as in to="/simple-string/" you can do it on your own. If you used named routes to="{ name: 'foobar' }" it is handled by vue-router already and will include the trailing slash (or not)

@pimlie
Copy link

pimlie commented Aug 30, 2019

If you use fixed URLs as in to="/simple-string/" you can do it on your own

Thanks, this is why I recommend a normalization utility. Maybe even within nuxt-link itself, but should also be accessible outside for easy use in eg the sitemap-module.

If we support this feature switching between having a trailing slash or not should be as effortless as possible, preferable even with just toggling the setting if you use the normalization utility everywhere.

@manniL
Copy link
Member Author

manniL commented Aug 31, 2019

Thanks, this is why I recommend a normalization utility. Maybe even within nuxt-link itself, but should also be accessible outside for easy use in eg the sitemap-module.

Now I got it, that'd be a nice DX improvement and also guarantee that all modules implement the same normalization.

A utility directly included in the nuxt-link component is also a nice idea, but could be more difficult than it seems on the first look (taking e.g. query params and programmatic usage into consideration)

@pi0 pi0 merged commit 7c90310 into dev Sep 1, 2019
@pi0
Copy link
Member

pi0 commented Sep 1, 2019

TODO for myself: add multi scope handling for release-notes generator!

@pi0 pi0 deleted the feat/trailing-slash-settings branch September 1, 2019 14:37
@pi0 pi0 mentioned this pull request Sep 26, 2019
@pi0 pi0 removed the WIP label Mar 17, 2020
@danielroe danielroe added the 2.x label Jan 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants