Repository: nuxt/nuxt.js
Pull request #5470 (2019-04-05 11:20:32)

fix: improve `router.base` handling
<!--- Provide a general summary of your changes in the title above -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [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

This PR addresses some problems with `router.base` handling and is complementary to nuxt/loading-screen#8.

- Always sanitize router base to end with `/`. Previously we were just mentioning it in the docs.
- Append router base to the listener computed URL. fixes issue with `-o` and CLI banner.

![image](https://user-images.githubusercontent.com/5158436/55624220-8184ac00-57ba-11e9-96d0-d79a443aed5c.png)

## Checklist:
<!--- Put an `x` in all the boxes that apply. -->
<!--- If your change requires a documentation PR, please link it appropriately -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] 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: # [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=h1) Report
> Merging [#5470](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=desc) into [dev](https://codecov.io/gh/nuxt/nuxt.js/commit/3cdce79d133da0ff0dd8c243e478fe89d5aa771b?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##              dev    #5470      +/-   ##
==========================================
+ Coverage   96.13%   96.13%   +<.01%     
==========================================
  Files          74       74              
  Lines        2559     2562       +3     
  Branches      651      652       +1     
==========================================
+ Hits         2460     2463       +3     
  Misses         83       83              
  Partials       16       16
```


| [Impacted Files](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/server/src/server.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvc2VydmVyL3NyYy9zZXJ2ZXIuanM=) | `97.72% <ø> (ø)` | :arrow_up: |
| [packages/config/src/options.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvY29uZmlnL3NyYy9vcHRpb25zLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/server/src/listener.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvc2VydmVyL3NyYy9saXN0ZW5lci5qcw==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?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/5470?src=pr&el=footer). Last update [3cdce79...e368719](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

codecov-io: # [Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=h1) Report
> Merging [#5470](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=desc) into [dev](https://codecov.io/gh/nuxt/nuxt.js/commit/3cdce79d133da0ff0dd8c243e478fe89d5aa771b?src=pr&el=desc) will **increase** coverage by `<.01%`.
> The diff coverage is `100%`.

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

```diff
@@            Coverage Diff             @@
##              dev    #5470      +/-   ##
==========================================
+ Coverage   96.13%   96.13%   +<.01%     
==========================================
  Files          74       74              
  Lines        2559     2562       +3     
  Branches      651      652       +1     
==========================================
+ Hits         2460     2463       +3     
  Misses         83       83              
  Partials       16       16
```


| [Impacted Files](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [packages/server/src/server.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvc2VydmVyL3NyYy9zZXJ2ZXIuanM=) | `97.72% <ø> (ø)` | :arrow_up: |
| [packages/config/src/options.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvY29uZmlnL3NyYy9vcHRpb25zLmpz) | `100% <100%> (ø)` | :arrow_up: |
| [packages/server/src/listener.js](https://codecov.io/gh/nuxt/nuxt.js/pull/5470/diff?src=pr&el=tree#diff-cGFja2FnZXMvc2VydmVyL3NyYy9saXN0ZW5lci5qcw==) | `100% <100%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?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/5470?src=pr&el=footer). Last update [3cdce79...e368719](https://codecov.io/gh/nuxt/nuxt.js/pull/5470?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

clarkdo: Is this a minor breaking change for users are using url without trailing slash ?

Patch:
diff --git a/packages/config/src/options.js b/packages/config/src/options.js
index fb8d5dd85..f985b4c94 100644
--- a/packages/config/src/options.js
+++ b/packages/config/src/options.js
@@ -22,6 +22,7 @@ export function getNuxtConfig(_options) {
   if (options.loading === true) {
     delete options.loading
   }
+
   if (
     options.router &&
     options.router.middleware &&
@@ -29,15 +30,19 @@ export function getNuxtConfig(_options) {
   ) {
     options.router.middleware = [options.router.middleware]
   }
+
   if (options.router && typeof options.router.base === 'string') {
     options._routerBaseSpecified = true
   }
+
   if (typeof options.transition === 'string') {
     options.transition = { name: options.transition }
   }
+
   if (typeof options.layoutTransition === 'string') {
     options.layoutTransition = { name: options.layoutTransition }
   }
+
   if (typeof options.extensions === 'string') {
     options.extensions = [options.extensions]
   }
@@ -69,6 +74,11 @@ export function getNuxtConfig(_options) {
 
   defaultsDeep(options, nuxtConfig)
 
+  // Sanitize router.base
+  if (!/\/$/.test(options.router.base)) {
+    options.router.base += '/'
+  }
+
   // Check srcDir and generate.dir existence
   const hasSrcDir = isNonEmptyString(options.srcDir)
   const hasGenerateDir = isNonEmptyString(options.generate.dir)
@@ -221,7 +231,7 @@ export function getNuxtConfig(_options) {
     })
   }
 
-  // vue config
+  // Vue config
   const vueConfig = options.vue.config
 
   if (vueConfig.silent === undefined) {
diff --git a/packages/server/src/listener.js b/packages/server/src/listener.js
index 04f13a442..dfbb0e549 100644
--- a/packages/server/src/listener.js
+++ b/packages/server/src/listener.js
@@ -6,7 +6,7 @@ import consola from 'consola'
 import pify from 'pify'
 
 export default class Listener {
-  constructor({ port, host, socket, https, app, dev }) {
+  constructor({ port, host, socket, https, app, dev, baseURL }) {
     // Options
     this.port = port
     this.host = host
@@ -14,6 +14,7 @@ export default class Listener {
     this.https = https
     this.app = app
     this.dev = dev
+    this.baseURL = baseURL
 
     // After listen
     this.listening = false
@@ -46,7 +47,7 @@ export default class Listener {
         case '0.0.0.0': this.host = ip.address(); break
       }
       this.port = address.port
-      this.url = `http${this.https ? 's' : ''}://${this.host}:${this.port}`
+      this.url = `http${this.https ? 's' : ''}://${this.host}:${this.port}${this.baseURL}`
       return
     }
     this.url = `unix+http://${address}`
diff --git a/packages/server/src/server.js b/packages/server/src/server.js
index e937f00fb..483aa091f 100644
--- a/packages/server/src/server.js
+++ b/packages/server/src/server.js
@@ -239,7 +239,8 @@ export default class Server {
       socket: socket || this.options.server.socket,
       https: this.options.server.https,
       app: this.app,
-      dev: this.options.dev
+      dev: this.options.dev,
+      baseURL: this.options.router.base
     })
 
     // Listen


Test patch:
diff --git a/packages/config/test/options.test.js b/packages/config/test/options.test.js
index e744db32e..87b458d81 100644
--- a/packages/config/test/options.test.js
+++ b/packages/config/test/options.test.js
@@ -227,3 +227,10 @@ describe('config: options', () => {
     })
   })
 })
+
+describe('config: router', () => {
+  test('should sanitize router.base', () => {
+    const config = getNuxtConfig({ router: { base: '/foo' } })
+    expect(config.router.base).toBe('/foo/')
+  })
+})
diff --git a/packages/server/test/listener.test.js b/packages/server/test/listener.test.js
index e53624fd6..f37842157 100644
--- a/packages/server/test/listener.test.js
+++ b/packages/server/test/listener.test.js
@@ -228,7 +228,8 @@ describe('server: listener', () => {
   test('should compute http url', () => {
     const options = {
       port: 3000,
-      host: 'localhost'
+      host: 'localhost',
+      baseURL: '/'
     }
     const listener = new Listener(options)
     listener.server = mockServer()
@@ -240,7 +241,7 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('localhost')
     expect(listener.port).toEqual(3000)
-    expect(listener.url).toEqual('http://localhost:3000')
+    expect(listener.url).toEqual('http://localhost:3000/')
 
     listener.server.address.mockReturnValueOnce({
       address: '127.0.0.1',
@@ -249,7 +250,7 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('localhost')
     expect(listener.port).toEqual(3001)
-    expect(listener.url).toEqual('http://localhost:3001')
+    expect(listener.url).toEqual('http://localhost:3001/')
 
     ip.address.mockReturnValueOnce('192.168.0.1')
     listener.server.address.mockReturnValueOnce({
@@ -259,14 +260,15 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('192.168.0.1')
     expect(listener.port).toEqual(3002)
-    expect(listener.url).toEqual('http://192.168.0.1:3002')
+    expect(listener.url).toEqual('http://192.168.0.1:3002/')
   })
 
   test('should compute https url', () => {
     const options = {
       port: 3000,
       host: 'localhost',
-      https: true
+      https: true,
+      baseURL: '/'
     }
     const listener = new Listener(options)
     listener.server = mockServer()
@@ -278,7 +280,7 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('localhost')
     expect(listener.port).toEqual(3000)
-    expect(listener.url).toEqual('https://localhost:3000')
+    expect(listener.url).toEqual('https://localhost:3000/')
 
     listener.server.address.mockReturnValueOnce({
       address: '127.0.0.1',
@@ -287,7 +289,7 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('localhost')
     expect(listener.port).toEqual(3001)
-    expect(listener.url).toEqual('https://localhost:3001')
+    expect(listener.url).toEqual('https://localhost:3001/')
 
     ip.address.mockReturnValueOnce('192.168.0.1')
     listener.server.address.mockReturnValueOnce({
@@ -297,7 +299,7 @@ describe('server: listener', () => {
     listener.computeURL()
     expect(listener.host).toEqual('192.168.0.1')
     expect(listener.port).toEqual(3002)
-    expect(listener.url).toEqual('https://192.168.0.1:3002')
+    expect(listener.url).toEqual('https://192.168.0.1:3002/')
   })
 
   test('should compute unix socket url', () => {
diff --git a/packages/server/test/server.test.js b/packages/server/test/server.test.js
index 55e46e457..ae0727c4b 100644
--- a/packages/server/test/server.test.js
+++ b/packages/server/test/server.test.js
@@ -43,6 +43,9 @@ describe('server: server', () => {
       build: {
         publicPath: '__nuxt_test'
       },
+      router: {
+        base: '/foo/'
+      },
       render: {
         id: 'test-render',
         dist: {
@@ -485,7 +488,8 @@ describe('server: server', () => {
       socket: '/var/nuxt/unix.socket',
       https: undefined,
       app: server.app,
-      dev: server.options.dev
+      dev: server.options.dev,
+      baseURL: '/foo/'
     })
     expect(listener.listen).toBeCalledTimes(1)
     expect(server.listeners).toEqual([ listener ])
@@ -508,7 +512,8 @@ describe('server: server', () => {
     expect(Listener).toBeCalledWith({
       ...nuxt.options.server,
       app: server.app,
-      dev: server.options.dev
+      dev: server.options.dev,
+      baseURL: '/foo/'
     })
   })