mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
311e4ca0ee
Based on the we can change the routing to do SSR always. Also make sure pageLoader don't download the page via client side twice.
110 lines
2.8 KiB
JavaScript
110 lines
2.8 KiB
JavaScript
/* global window, document */
|
|
import mitt from 'mitt'
|
|
|
|
const webpackModule = module
|
|
|
|
export default class PageLoader {
|
|
constructor (buildId, assetPrefix) {
|
|
this.buildId = buildId
|
|
this.assetPrefix = assetPrefix
|
|
|
|
this.pageCache = {}
|
|
this.pageLoadedHandlers = {}
|
|
this.registerEvents = mitt()
|
|
this.loadingRoutes = {}
|
|
}
|
|
|
|
normalizeRoute (route) {
|
|
if (route[0] !== '/') {
|
|
throw new Error('Route name should start with a "/"')
|
|
}
|
|
|
|
if (route === '/') return route
|
|
return route.replace(/index$/, '').replace(/\/$/, '')
|
|
}
|
|
|
|
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)
|
|
})
|
|
}
|
|
|
|
return new Promise((resolve, reject) => {
|
|
const fire = ({ error, page }) => {
|
|
this.registerEvents.off(route, fire)
|
|
|
|
if (error) {
|
|
reject(error)
|
|
} else {
|
|
resolve(page)
|
|
}
|
|
}
|
|
|
|
this.registerEvents.on(route, fire)
|
|
|
|
// If the page is loading via SSR, we need to wait for it
|
|
// rather downloading it again.
|
|
if (document.getElementById(`__NEXT_PAGE__${route}`)) {
|
|
return
|
|
}
|
|
|
|
// Load the script if not asked to load yet.
|
|
if (!this.loadingRoutes[route]) {
|
|
this.loadScript(route)
|
|
this.loadingRoutes[route] = true
|
|
}
|
|
})
|
|
}
|
|
|
|
loadScript (route) {
|
|
route = this.normalizeRoute(route)
|
|
|
|
const script = document.createElement('script')
|
|
const url = `${this.assetPrefix}/_next/${encodeURIComponent(this.buildId)}/page${route}`
|
|
script.src = url
|
|
script.type = 'text/javascript'
|
|
script.onerror = () => {
|
|
const error = new Error(`Error when loading route: ${route}`)
|
|
this.registerEvents.emit(route, { error })
|
|
}
|
|
|
|
document.body.appendChild(script)
|
|
}
|
|
|
|
// This method if called by the route code.
|
|
registerPage (route, regFn) {
|
|
const register = () => {
|
|
const { error, page } = regFn()
|
|
this.pageCache[route] = { error, page }
|
|
this.registerEvents.emit(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]
|
|
}
|
|
}
|