rsnext/lib/page-loader.js
Arunoda Susiripala fb2f90bec1 Get rid of mitt.
2017-04-11 15:35:29 +05:30

105 lines
2.6 KiB
JavaScript

/* global window, document */
const webpackModule = module
export default class PageLoader {
constructor (buildId) {
this.buildId = buildId
this.pageCache = {}
this.pageLoadedHandlers = {}
this.loadingRoutes = {}
}
normalizeRoute (route) {
if (route[0] !== '/') {
throw new Error('Route name should start with a "/"')
}
if (route === '/') return route
return route.replace(/(\/)?(index)?$/, '')
}
loadPage (route) {
route = this.normalizeRoute(route)
const cachedPage = this.pageCache[route]
if (cachedPage) {
return new Promise((resolve, reject) => {
if (cachedPage.error) return reject(cachedPage.error)
return resolve(cachedPage.page)
})
}
if (this.loadingRoutes[route]) {
return this.loadingRoutes[route]
}
const loadingPromise = new Promise((resolve, reject) => {
this.loadScript(route, (error) => {
delete this.loadingRoutes[route]
if (error) return reject(error)
const cachedPage = this.pageCache[route]
if (cachedPage.error) return reject(cachedPage.error)
return resolve(cachedPage.page)
})
})
this.loadingRoutes[route] = loadingPromise
return loadingPromise
}
loadScript (route, fn) {
route = this.normalizeRoute(route)
const script = document.createElement('script')
const url = `/_next/${encodeURIComponent(this.buildId)}/page${route}`
script.src = url
script.type = 'text/javascript'
script.onerror = (e) => {
const error = new Error(`Network error occurred when loading route: ${route}`)
fn(error)
}
script.onload = () => {
fn()
}
document.body.appendChild(script)
}
// This method if called by the route code.
registerPage (route, regFn) {
const register = () => {
regFn((error, page) => {
route = this.normalizeRoute(route)
// add the page to the cache
this.pageCache[route] = { error, page }
})
}
// Wait for webpack to became idle if it's not.
// More info: https://github.com/zeit/next.js/pull/1511
if (webpackModule && webpackModule.hot && webpackModule.hot.status() !== 'idle') {
console.log(`Waiting webpack to became "idle" to initialize the page: "${route}"`)
const check = (status) => {
if (status === 'idle') {
webpackModule.hot.removeStatusHandler(check)
register()
}
}
webpackModule.hot.status(check)
} else {
register()
}
}
clearCache (route) {
route = this.normalizeRoute(route)
delete this.pageCache[route]
delete this.loadingRoutes[route]
}
}