1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00
next.js/lib/page-loader.js
Arunoda Susiripala dec85fe6c4 Add CDN support with assetPrefix (#1700)
* Introduce script tag based page loading system.

* Call ensurePage only in the dev mode.

* Implement router using the page-loader.

* Fix a typo and remove unwanted code.

* Fix some issues related to rendering.

* Fix production tests.

* Fix ondemand test cases.

* Fix unit tests.

* Get rid of eval completely.

* Remove all the inline code.

* Remove the json-pages plugin.

* Rename NEXT_PAGE_LOADER into __NEXT_PAGE_LOADER__

* Rename NEXT_LOADED_PAGES into __NEXT_LOADED_PAGES__

* Remove some unwanted code.

* Load everything async.

* Remove lib/eval-script.js
We no longer need it.

* Move webpack idle wait code to the page-loader.
Because that's the place to do it.

* Remove pageNotFound key from the error.

* Remove unused error field 'buildError'

* Add much better logic to normalize routes.

* Get rid of mitt.

* Introduce a better way to register pages.

* Came back to the mitt() based page-loader.

* Add link rel=preload support.

* Add assetPrefix support to add support for CDNs.

* Add assetPrefix support for preload links.

* Update readme.md
2017-04-17 21:18:43 -07:00

103 lines
2.6 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 "/"')
}
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)
})
}
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)
// 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]
}
}