1
0
Fork 0
mirror of https://github.com/terribleplan/next.js.git synced 2024-01-19 02:48:18 +00:00

Load everything async.

This commit is contained in:
Arunoda Susiripala 2017-04-06 11:41:13 +05:30
parent f6f175db73
commit e46edc2460
8 changed files with 130 additions and 142 deletions

View file

@ -34,30 +34,32 @@ if (window.__NEXT_LOADED_PAGES__) {
delete window.__NEXT_LOADED_PAGES__
}
const ErrorComponent = pageLoader.loadPageSync('/_error')
let Component
try {
Component = pageLoader.loadPageSync(pathname)
} catch (err) {
console.error(`${err.message}\n${err.stack}`)
Component = ErrorComponent
}
let lastAppProps
export const router = createRouter(pathname, query, getURL(), {
pageLoader,
Component,
ErrorComponent,
err
})
const headManager = new HeadManager()
const appContainer = document.getElementById('__next')
const errorContainer = document.getElementById('__next-error')
export default () => {
let lastAppProps
export let router
export let ErrorComponent
let Component
export default async () => {
ErrorComponent = await pageLoader.loadPage('/_error')
try {
Component = await pageLoader.loadPage(pathname)
} catch (err) {
console.error(`${err.message}\n${err.stack}`)
Component = ErrorComponent
}
router = createRouter(pathname, query, getURL(), {
pageLoader,
Component,
ErrorComponent,
err
})
const emitter = mitt()
router.subscribe(({ Component, props, hash, err }) => {
@ -120,7 +122,7 @@ async function doRender ({ Component, props, hash, err, emitter }) {
}
if (emitter) {
emitter.emit('before-reactdom-render', { Component })
emitter.emit('before-reactdom-render', { Component, ErrorComponent })
}
Component = Component || lastAppProps.Component
@ -135,6 +137,6 @@ async function doRender ({ Component, props, hash, err, emitter }) {
ReactDOM.render(createElement(App, appProps), appContainer)
if (emitter) {
emitter.emit('after-reactdom-render', { Component })
emitter.emit('after-reactdom-render', { Component, ErrorComponent })
}
}

View file

@ -1,14 +1,40 @@
import evalScript from '../lib/eval-script'
import 'react-hot-loader/patch'
import ReactReconciler from 'react-dom/lib/ReactReconciler'
const { __NEXT_DATA__: { errorComponent } } = window
const ErrorComponent = evalScript(errorComponent).default
require('react-hot-loader/patch')
import initOnDemandEntries from './on-demand-entries-client'
import initWebpackHMR from './webpack-hot-middleware-client'
const next = window.next = require('./')
const emitter = next.default()
next.default()
.then((emitter) => {
initOnDemandEntries()
initWebpackHMR()
let lastScroll
emitter.on('before-reactdom-render', ({ Component, ErrorComponent }) => {
// Remember scroll when ErrorComponent is being rendered to later restore it
if (!lastScroll && Component === ErrorComponent) {
const { pageXOffset, pageYOffset } = window
lastScroll = {
x: pageXOffset,
y: pageYOffset
}
}
})
emitter.on('after-reactdom-render', ({ Component, ErrorComponent }) => {
if (lastScroll && Component !== ErrorComponent) {
// Restore scroll after ErrorComponent was replaced with a page component by HMR
const { x, y } = lastScroll
window.scroll(x, y)
lastScroll = null
}
})
})
.catch((err) => {
console.error(`${err.message}\n${err.stack}`)
})
// This is a patch to catch most of the errors throw inside React components.
const originalMountComponent = ReactReconciler.mountComponent
@ -21,25 +47,3 @@ ReactReconciler.mountComponent = function (...args) {
throw err
}
}
let lastScroll
emitter.on('before-reactdom-render', ({ Component }) => {
// Remember scroll when ErrorComponent is being rendered to later restore it
if (!lastScroll && Component === ErrorComponent) {
const { pageXOffset, pageYOffset } = window
lastScroll = {
x: pageXOffset,
y: pageYOffset
}
}
})
emitter.on('after-reactdom-render', ({ Component }) => {
if (lastScroll && Component !== ErrorComponent) {
// Restore scroll after ErrorComponent was replaced with a page component by HMR
const { x, y } = lastScroll
window.scroll(x, y)
lastScroll = null
}
})

View file

@ -1,3 +1,6 @@
import next from './'
next()
.catch((err) => {
console.error(`${err.message}\n${err.stack}`)
})

View file

@ -3,31 +3,33 @@
import Router from '../lib/router'
import fetch from 'unfetch'
Router.ready(() => {
Router.router.events.on('routeChangeComplete', ping)
})
async function ping () {
try {
const url = `/_next/on-demand-entries-ping?page=${Router.pathname}`
const res = await fetch(url)
const payload = await res.json()
if (payload.invalid) {
location.reload()
}
} catch (err) {
console.error(`Error with on-demand-entries-ping: ${err.message}`)
}
}
async function runPinger () {
while (true) {
await new Promise((resolve) => setTimeout(resolve, 5000))
await ping()
}
}
runPinger()
.catch((err) => {
console.error(err)
export default () => {
Router.ready(() => {
Router.router.events.on('routeChangeComplete', ping)
})
async function ping () {
try {
const url = `/_next/on-demand-entries-ping?page=${Router.pathname}`
const res = await fetch(url)
const payload = await res.json()
if (payload.invalid) {
location.reload()
}
} catch (err) {
console.error(`Error with on-demand-entries-ping: ${err.message}`)
}
}
async function runPinger () {
while (true) {
await new Promise((resolve) => setTimeout(resolve, 5000))
await ping()
}
}
runPinger()
.catch((err) => {
console.error(err)
})
}

View file

@ -1,48 +1,50 @@
import webpackHotMiddlewareClient from 'webpack-hot-middleware/client?overlay=false&reload=true'
import Router from '../lib/router'
const handlers = {
reload (route) {
if (route === '/_error') {
for (const r of Object.keys(Router.components)) {
const { err } = Router.components[r]
if (err) {
// reload all error routes
// which are expected to be errors of '/_error' routes
Router.reload(r)
export default () => {
const handlers = {
reload (route) {
if (route === '/_error') {
for (const r of Object.keys(Router.components)) {
const { err } = Router.components[r]
if (err) {
// reload all error routes
// which are expected to be errors of '/_error' routes
Router.reload(r)
}
}
return
}
return
}
if (route === '/_document') {
window.location.reload()
return
}
if (route === '/_document') {
window.location.reload()
return
}
Router.reload(route)
},
change (route) {
if (route === '/_document') {
window.location.reload()
return
}
const { err } = Router.components[route] || {}
if (err) {
// reload to recover from runtime errors
Router.reload(route)
},
change (route) {
if (route === '/_document') {
window.location.reload()
return
}
const { err } = Router.components[route] || {}
if (err) {
// reload to recover from runtime errors
Router.reload(route)
}
}
}
}
webpackHotMiddlewareClient.subscribe((obj) => {
const fn = handlers[obj.action]
if (fn) {
const data = obj.data || []
fn(...data)
} else {
throw new Error('Unexpected action ' + obj.action)
}
})
webpackHotMiddlewareClient.subscribe((obj) => {
const fn = handlers[obj.action]
if (fn) {
const data = obj.data || []
fn(...data)
} else {
throw new Error('Unexpected action ' + obj.action)
}
})
}

View file

@ -103,8 +103,8 @@ export class NextScript extends Component {
{staticMarkup ? null : <script dangerouslySetInnerHTML={{
__html: `__NEXT_DATA__ = ${htmlescape(__NEXT_DATA__)}; module={};`
}} />}
<script type='text/javascript' src={`/_next/${buildId}/page${pathname}`} />
<script type='text/javascript' src={`/_next/${buildId}/page/_error`} />
<script async type='text/javascript' src={`/_next/${buildId}/page${pathname}`} />
<script async type='text/javascript' src={`/_next/${buildId}/page/_error`} />
{staticMarkup ? null : this.getScripts()}
</div>
}

View file

@ -5,7 +5,6 @@ import onDemandEntryHandler from './on-demand-entry-handler'
import isWindowsBash from 'is-windows-bash'
import webpack from './build/webpack'
import clean from './build/clean'
import readPage from './read-page'
import getConfig from './config'
export default class HotReloader {
@ -202,7 +201,6 @@ export default class HotReloader {
function deleteCache (path) {
delete require.cache[path]
delete readPage.cache[path]
}
function diff (a, b) {

View file

@ -1,23 +0,0 @@
import fs from 'mz/fs'
import resolve from './resolve'
/**
* resolve a JSON page like `require.resolve`,
* and read and cache the file content
*/
async function readPage (path) {
const f = await resolve(path)
if (cache.hasOwnProperty(f)) {
return cache[f]
}
const source = await fs.readFile(f, 'utf8')
cache[f] = source
return source
}
export default readPage
export const cache = {}
readPage.cache = cache