/* global window */ import _Router from './router' const SingletonRouter = { router: null, // holds the actual router instance readyCallbacks: [], ready (cb) { if (this.router) return cb() if (typeof window !== 'undefined') { this.readyCallbacks.push(cb) } } } // Create public properties and methods of the router in the SingletonRouter const propertyFields = ['components', 'pathname', 'route', 'query', 'asPath'] const coreMethodFields = ['push', 'replace', 'reload', 'back', 'prefetch'] const routerEvents = ['routeChangeStart', 'beforeHistoryChange', 'routeChangeComplete', 'routeChangeError'] propertyFields.forEach((field) => { // Here we need to use Object.defineProperty because, we need to return // the property assigned to the actual router // The value might get changed as we change routes and this is the // proper way to access it Object.defineProperty(SingletonRouter, field, { get () { throwIfNoRouter() return SingletonRouter.router[field] } }) }) coreMethodFields.forEach((field) => { SingletonRouter[field] = (...args) => { throwIfNoRouter() return SingletonRouter.router[field](...args) } }) routerEvents.forEach((event) => { SingletonRouter.ready(() => { SingletonRouter.router.events.on(event, (...args) => { const eventField = `on${event.charAt(0).toUpperCase()}${event.substring(1)}` if (SingletonRouter[eventField]) { SingletonRouter[eventField](...args) } }) }) }) function throwIfNoRouter () { if (!SingletonRouter.router) { const message = 'No router instance found.\n' + 'You should only use "next/router" inside the client side of your app.\n' throw new Error(message) } } // Export the SingletonRouter and this is the public API. export default SingletonRouter // INTERNAL APIS // ------------- // (do not use following exports inside the app) // Create a router and assign it as the singleton instance. // This is used in client side when we are initilizing the app. // This should **not** use inside the server. export const createRouter = function (...args) { SingletonRouter.router = new _Router(...args) SingletonRouter.readyCallbacks.forEach(cb => cb()) SingletonRouter.readyCallbacks = [] return SingletonRouter.router } // 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 { console.warn(`An app update detected. Loading the SSR version of "${nextRoute}"`) window.location.href = nextRoute } } export function _rewriteUrlForNextExport (url) { // If there are no query strings if (!/\?/.test(url)) { return rewritePath(url) } const [path, qs] = url.split('?') const newPath = rewritePath(path) return `${newPath}?${qs}` function rewritePath (path) { // If ends with slash simply return that path if (/\/$/.test(path)) { return path } return `${path}/` } }