Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions lib/router/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* global window, location */
import _Router from './router'

const SingletonRouter = {
Expand Down Expand Up @@ -75,3 +76,11 @@ export const createRouter = function (...args) {

// Export the actual Router class, which is usually used inside the server
export const Router = _Router

export function _notifyBuildIdMismatch (nextRoute) {
if (SingletonRouter.onAppUpdated) {
SingletonRouter.onAppUpdated(nextRoute)
} else {
location.href = nextRoute
}
}
27 changes: 21 additions & 6 deletions lib/router/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import evalScript from '../eval-script'
import shallowEquals from '../shallow-equals'
import PQueue from '../p-queue'
import { loadGetInitialProps, getLocationOrigin } from '../utils'
import { _notifyBuildIdMismatch } from './'

// Add "fetch" polyfill for older browsers
if (typeof window !== 'undefined') {
Expand Down Expand Up @@ -75,7 +76,7 @@ export default class Router extends EventEmitter {
data,
props,
error
} = await this.getRouteInfo(route, pathname, query)
} = await this.getRouteInfo(route, pathname, query, as)

if (error && error.cancelled) {
this.emit('routeChangeError', error, as)
Expand Down Expand Up @@ -116,7 +117,7 @@ export default class Router extends EventEmitter {
data,
props,
error
} = await this.getRouteInfo(route, pathname, query)
} = await this.getRouteInfo(route, pathname, query, url)

if (error && error.cancelled) {
this.emit('routeChangeError', error, url)
Expand Down Expand Up @@ -162,7 +163,7 @@ export default class Router extends EventEmitter {
this.emit('routeChangeStart', as)
const {
data, props, error
} = await this.getRouteInfo(route, pathname, query)
} = await this.getRouteInfo(route, pathname, query, as)

if (error && error.cancelled) {
this.emit('routeChangeError', error, as)
Expand All @@ -189,11 +190,16 @@ export default class Router extends EventEmitter {
}
}

async getRouteInfo (route, pathname, query) {
async getRouteInfo (route, pathname, query, as) {
const routeInfo = {}

try {
const { Component, err, jsonPageRes } = routeInfo.data = await this.fetchComponent(route)
routeInfo.data = await this.fetchComponent(route, as)
if (!routeInfo.data) {
return null
}

const { Component, err, jsonPageRes } = routeInfo.data
const ctx = { err, pathname, query, jsonPageRes }
routeInfo.props = await this.getInitialProps(Component, ctx)
} catch (err) {
Expand Down Expand Up @@ -229,7 +235,7 @@ export default class Router extends EventEmitter {
return this.prefetchQueue.add(() => this.fetchRoute(route))
}

async fetchComponent (route) {
async fetchComponent (route, as) {
let data = this.components[route]
if (data) return data

Expand All @@ -240,6 +246,15 @@ export default class Router extends EventEmitter {

const jsonPageRes = await this.fetchRoute(route)
const jsonData = await jsonPageRes.json()

if (jsonData.buildIdMismatch) {
_notifyBuildIdMismatch(as)

const error = Error('Abort due to BUILD_ID mismatch')
error.cancelled = true
throw error
}

const newData = {
...loadComponent(jsonData),
jsonPageRes
Expand Down
12 changes: 12 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ Here's a list of supported events:
- `routeChangeStart(url)` - Fires when a route starts to change
- `routeChangeComplete(url)` - Fires when a route changed completely
- `routeChangeError(err, url)` - Fires when there's an error when changing routes
- `appUpdated(nextRoute)` - Fires when switching pages and there's a new version of the app

> Here `url` is the URL shown in the browser. If you call `Router.push(url, as)` (or similar), then the value of `url` will be `as`.

Expand Down Expand Up @@ -337,6 +338,17 @@ Router.onRouteChangeError = (err, url) => {
}
```

If you change a route while in between a new deployment, we can't navigate the app via client side. We need to do a full browser navigation. We do it automatically for you.

But you can customize that via `Route.onAppUpdated` event like this:

```js
Router.onAppUpdated = (nextUrl) => {
// persist the local state
location.href = nextUrl
}
```

### Prefetching Pages

<p><details>
Expand Down
28 changes: 21 additions & 7 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,19 +81,30 @@ export default class Server {
},

'/_next/:buildId/main.js': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
if (!this.handleBuildId(params.buildId, res)) {
throwBuildIdMismatchError()
}

const p = join(this.dir, '.next/main.js')
await this.serveStatic(req, res, p)
},

'/_next/:buildId/commons.js': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
if (!this.handleBuildId(params.buildId, res)) {
throwBuildIdMismatchError()
}

const p = join(this.dir, '.next/commons.js')
await this.serveStatic(req, res, p)
},

'/_next/:buildId/pages/:path*': async (req, res, params) => {
this.handleBuildId(params.buildId, res)
if (!this.handleBuildId(params.buildId, res)) {
res.setHeader('Content-Type', 'application/json')
res.end(JSON.stringify({ buildIdMismatch: true }))
return
}

const paths = params.path || ['index']
const pathname = `/${paths.join('/')}`
await this.renderJSON(req, res, pathname)
Expand Down Expand Up @@ -277,14 +288,13 @@ export default class Server {
}

handleBuildId (buildId, res) {
if (this.dev) return
if (this.dev) return true
if (buildId !== this.renderOpts.buildId) {
const errorMessage = 'Build id mismatch!' +
'Seems like the server and the client version of files are not the same.'
throw new Error(errorMessage)
return false
}

res.setHeader('Cache-Control', 'max-age=365000000, immutable')
return true
}

getCompilationError (page) {
Expand All @@ -298,3 +308,7 @@ export default class Server {
if (p) return errors.get(p)[0]
}
}

function throwBuildIdMismatchError () {
throw new Error('BUILD_ID Mismatched!')
}
4 changes: 2 additions & 2 deletions test/integration/basic/test/misc.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* global describe, test, expect */

export default function ({ app }) {
export default function (context) {
describe('Misc', () => {
test('finishes response', async () => {
const res = {
Expand All @@ -9,7 +9,7 @@ export default function ({ app }) {
this.finished = true
}
}
const html = await app.renderToHTML({}, res, '/finish-response', {})
const html = await context.app.renderToHTML({}, res, '/finish-response', {})
expect(html).toBeFalsy()
})
})
Expand Down