Repository: nuxt/nuxt.js
Pull request #7604 (2020-06-25 11:30:25)

fix(utils): flat routes if child routes have absolute paths
Fixed `flatRoutes` function to work properly if children routes have absolute paths.
This was working fine in 2.12, it did break in 2.13.

## Types of changes
- [x] 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
I am using `nuxt.js` along with `nuxt-18n`. I use SEO-friendly, localized routes.
For this to work, you have to configure pages to have absolute paths.

Here is a snapshot of my config:
![image](https://user-images.githubusercontent.com/2473784/85711657-c6f70700-b6e7-11ea-935b-921cb1b42e59.png)

However, it does not work well:
![image](https://user-images.githubusercontent.com/2473784/85711707-d4ac8c80-b6e7-11ea-832e-d8aa94ceb4b9.png)

Routes are not properly concatenated. When I look into `router.js` generated file, it looks fine:
![image](https://user-images.githubusercontent.com/2473784/85711777-e726c600-b6e7-11ea-8323-f6afaddd3622.png)

The reason behind this is, that `flatRoutes` function concatenates parent path and child path, even if child path is absolute.

## 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)
- [x] All new and existing tests are passing.



codecov-commenter: # [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=h1) Report
> Merging [#7604](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=desc) into [dev](https://codecov.io/gh/nuxt/nuxt.js/commit/d89812f24164e95585d0ffebf8e9ca021071d0a3&el=desc) will **increase** coverage by `0.00%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/nuxt/nuxt.js/pull/7604/graphs/tree.svg?width=650&height=150&src=pr&token=nGD1PtMB3M)](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=tree)

```diff
@@           Coverage Diff           @@
##              dev    #7604   +/-   ##
=======================================
  Coverage   70.28%   70.28%           
=======================================
  Files          88       88           
  Lines        3745     3746    +1     
  Branches     1019     1018    -1     
=======================================
+ Hits         2632     2633    +1     
  Misses        904      904           
  Partials      209      209           
```

| Flag | Coverage Δ | |
|---|---|---|
| #unittests | `70.28% <100.00%> (+<0.01%)` | :arrow_up: |

| [Impacted Files](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/utils/src/route.js](https://codecov.io/gh/nuxt/nuxt.js/pull/7604/diff?src=pr&el=tree#diff-cGFja2FnZXMvdXRpbHMvc3JjL3JvdXRlLmpz) | `96.57% <100.00%> (+0.02%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=footer). Last update [d89812f...7076b02](https://codecov.io/gh/nuxt/nuxt.js/pull/7604?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

pi0: Hi @kedrzu. This fix looks good to me btw why you are not using [alias](https://router.vuejs.org/guide/essentials/redirect-and-alias.html#alias)?
kedrzu: I don't think this would be an alternative.
What I use is a basic solution when using `nuxt-i18n`, described here: https://nuxt-community.github.io/nuxt-i18n/routing.html#custom-paths

I don't think aliasing would be properly recognized by `nuxt-i18n` to display page in proper language. I think in `nuxt-i18n` routes are recognized by their name:
![image](https://user-images.githubusercontent.com/2473784/85715711-07588400-b6ec-11ea-8e4d-578cb9d25d90.png)

Language is attached to the end of the route name. I don't want to mess with that :)
kedrzu: @pi0 maybe it would be better to cherry pick the commit to 2.x branch?

Patch:
diff --git a/packages/core/src/module.js b/packages/core/src/module.js
index 1b578433c..e22c94583 100644
--- a/packages/core/src/module.js
+++ b/packages/core/src/module.js
@@ -194,7 +194,12 @@ export default class ModuleContainer {
     const key = (handler.meta && handler.meta.name) || src
     if (typeof key === 'string') {
       if (this.requiredModules[key]) {
-        return
+        if (key === src) {
+          // TODO: Skip with nuxt3
+          consola.warn('Modules should be only specified once:', key)
+        } else {
+          return
+        }
       }
       this.requiredModules[key] = { src, options, handler }
     }
diff --git a/packages/utils/src/route.js b/packages/utils/src/route.js
index 3c08109d6..95dc8f238 100644
--- a/packages/utils/src/route.js
+++ b/packages/utils/src/route.js
@@ -13,14 +13,19 @@ export const flatRoutes = function flatRoutes (router, fileName = '', routes = [
       if (fileName === '' && r.path === '/') {
         routes.push('/')
       }
+
       return flatRoutes(r.children, fileName + r.path + '/', routes)
     }
     fileName = fileName.replace(/\/+/g, '/')
-    routes.push(
-      (r.path === '' && fileName[fileName.length - 1] === '/'
-        ? fileName.slice(0, -1)
-        : fileName) + r.path
-    )
+
+    // if child path is already absolute, do not make any concatenations
+    if (r.path && r.path.startsWith('/')) {
+      routes.push(r.path)
+    } else if (r.path === '' && fileName[fileName.length - 1] === '/') {
+      routes.push(fileName.slice(0, -1) + r.path)
+    } else {
+      routes.push(fileName + r.path)
+    }
   })
   return routes
 }


Test patch:
diff --git a/packages/utils/test/route.test.js b/packages/utils/test/route.test.js
index 4ec0ee35b..7422d55c1 100644
--- a/packages/utils/test/route.test.js
+++ b/packages/utils/test/route.test.js
@@ -40,6 +40,37 @@ describe('util: route', () => {
     expect(routes).toEqual(['/', '/foo/bar', '/foo/baz'])
   })
 
+  test('should flat absolute routes', () => {
+    const routes = flatRoutes([
+      {
+        name: 'foo',
+        path: '/foo',
+        children: [
+          { name: 'foo-bar', path: '/foo/bar' },
+          { name: 'foo-baz', path: '/foo/baz' }
+        ]
+      }
+    ])
+
+    expect(routes).toEqual(['/foo/bar', '/foo/baz'])
+  })
+
+  test('should flat absolute routes with empty path', () => {
+    const routes = flatRoutes([
+      {
+        name: 'foo',
+        path: '/foo',
+        children: [
+          { name: 'foo-root', path: '' },
+          { name: 'foo-bar', path: '/foo/bar' },
+          { name: 'foo-baz', path: '/foo/baz' }
+        ]
+      }
+    ])
+
+    expect(routes).toEqual(['/foo', '/foo/bar', '/foo/baz'])
+  })
+
   describe('util: route guard', () => {
     test('should guard parent dir', () => {
       expect(() => {