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

Remove react-hot-loader (#4500)

Fixes #4494
This commit is contained in:
Tim Neutkens 2018-05-31 11:47:29 +02:00 committed by GitHub
parent 0f9ea55023
commit 86d01706a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 517 additions and 92 deletions

View file

@ -1,2 +1,3 @@
[ignore] [ignore]
<PROJECT_ROOT>/examples/.* <PROJECT_ROOT>/examples/.*
<PROJECT_ROOT>/.*.json

View file

@ -7,7 +7,7 @@ install:
# Install Google Chrome for e2e testing # Install Google Chrome for e2e testing
- choco install --ignore-checksums googlechrome - choco install --ignore-checksums googlechrome
# Get the latest stable version of Node.js or io.js # Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version - ps: Install-Product node $env:nodejs_version x64
# install modules # install modules
- npm install - npm install

View file

@ -0,0 +1,41 @@
// @flow
import React from 'react'
import {applySourcemaps} from './source-map-support'
import ErrorDebug, {styles} from '../lib/error-debug'
import type {RuntimeError, ErrorReporterProps} from './error-boundary'
type State = {|
mappedError: null | RuntimeError
|}
// This component is only used in development, sourcemaps are applied on the fly because componentDidCatch is not async
class DevErrorOverlay extends React.Component<ErrorReporterProps, State> {
state = {
mappedError: null
}
componentDidMount () {
const {error} = this.props
// Since componentDidMount doesn't handle errors we use then/catch here
applySourcemaps(error).then(() => {
this.setState({mappedError: error})
}).catch((caughtError) => {
this.setState({mappedError: caughtError})
})
}
render () {
const {mappedError} = this.state
const {info} = this.props
if (mappedError === null) {
return <div style={styles.errorDebug}>
<h1 style={styles.heading}>Loading stacktrace...</h1>
</div>
}
return <ErrorDebug error={mappedError} info={info} />
}
}
export default DevErrorOverlay

66
client/error-boundary.js Normal file
View file

@ -0,0 +1,66 @@
// @flow
import * as React from 'react'
import {polyfill} from 'react-lifecycles-compat'
type ComponentDidCatchInfo = {
componentStack: string
}
export type Info = null | ComponentDidCatchInfo
export type RuntimeError = Error & {|
module: ?{|
rawRequest: string
|}
|}
export type ErrorReporterProps = {|error: RuntimeError, info: Info|}
type ErrorReporterComponent = React.ComponentType<ErrorReporterProps>
type Props = {|
ErrorReporter: null | ErrorReporterComponent,
onError: (error: RuntimeError, info: ComponentDidCatchInfo) => void,
children: React.ComponentType<*>
|}
type State = {|
error: null | RuntimeError,
info: Info
|}
class ErrorBoundary extends React.Component<Props, State> {
state = {
error: null,
info: null
}
static getDerivedStateFromProps () {
return {
error: null,
info: null
}
}
componentDidCatch (error: RuntimeError, info: ComponentDidCatchInfo) {
const {onError} = this.props
// onError is provided in production
if (onError) {
onError(error, info)
} else {
this.setState({ error, info })
}
}
render () {
const {ErrorReporter, children} = this.props
const {error, info} = this.state
if (ErrorReporter && error) {
return <ErrorReporter error={error} info={info} />
}
return React.Children.only(children)
}
}
// Makes sure we can use React 16.3 lifecycles and still support older versions of React.
polyfill(ErrorBoundary)
export default ErrorBoundary

View file

@ -7,6 +7,7 @@ import { loadGetInitialProps, getURL } from '../lib/utils'
import PageLoader from '../lib/page-loader' import PageLoader from '../lib/page-loader'
import * as asset from '../lib/asset' import * as asset from '../lib/asset'
import * as envConfig from '../lib/runtime-config' import * as envConfig from '../lib/runtime-config'
import ErrorBoundary from './error-boundary'
// Polyfill Promise globally // Polyfill Promise globally
// This is needed because Webpack2's dynamic loading(common chunks) code // This is needed because Webpack2's dynamic loading(common chunks) code
@ -66,8 +67,7 @@ const errorContainer = document.getElementById('__next-error')
let lastAppProps let lastAppProps
export let router export let router
export let ErrorComponent export let ErrorComponent
let HotAppContainer let DevErrorOverlay
let ErrorDebugComponent
let Component let Component
let App let App
let stripAnsi = (s) => s let stripAnsi = (s) => s
@ -76,8 +76,7 @@ let applySourcemaps = (e) => e
export const emitter = new EventEmitter() export const emitter = new EventEmitter()
export default async ({ export default async ({
HotAppContainer: passedHotAppContainer, DevErrorOverlay: passedDevErrorOverlay,
ErrorDebugComponent: passedDebugComponent,
stripAnsi: passedStripAnsi, stripAnsi: passedStripAnsi,
applySourcemaps: passedApplySourcemaps applySourcemaps: passedApplySourcemaps
} = {}) => { } = {}) => {
@ -88,8 +87,7 @@ export default async ({
stripAnsi = passedStripAnsi || stripAnsi stripAnsi = passedStripAnsi || stripAnsi
applySourcemaps = passedApplySourcemaps || applySourcemaps applySourcemaps = passedApplySourcemaps || applySourcemaps
HotAppContainer = passedHotAppContainer DevErrorOverlay = passedDevErrorOverlay
ErrorDebugComponent = passedDebugComponent
ErrorComponent = await pageLoader.loadPage('/_error') ErrorComponent = await pageLoader.loadPage('/_error')
App = await pageLoader.loadPage('/_app') App = await pageLoader.loadPage('/_app')
@ -115,12 +113,12 @@ export default async ({
err: initialErr err: initialErr
}) })
router.subscribe(({ Component, props, hash, err }) => { router.subscribe(({ App, Component, props, hash, err }) => {
render({ Component, props, err, hash, emitter }) render({ App, Component, props, err, hash, emitter })
}) })
const hash = location.hash.substring(1) const hash = location.hash.substring(1)
render({ Component, props, hash, err: initialErr, emitter }) render({ App, Component, props, hash, err: initialErr, emitter })
return emitter return emitter
} }
@ -143,14 +141,14 @@ export async function render (props) {
// 404 and 500 errors are special kind of errors // 404 and 500 errors are special kind of errors
// and they are still handle via the main render method. // and they are still handle via the main render method.
export async function renderError (props) { export async function renderError (props) {
const {err} = props const {err, errorInfo} = props
// In development we apply sourcemaps to the error // In development we apply sourcemaps to the error
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
await applySourcemaps(err) await applySourcemaps(err)
} }
const str = stripAnsi(`${err.message}\n${err.stack}${err.info ? `\n\n${err.info.componentStack}` : ''}`) const str = stripAnsi(`${err.message}\n${err.stack}${errorInfo ? `\n\n${errorInfo.componentStack}` : ''}`)
console.error(str) console.error(str)
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
@ -159,7 +157,7 @@ export async function renderError (props) {
// Otherwise, we need to face issues when the issue is fixed and // Otherwise, we need to face issues when the issue is fixed and
// it's get notified via HMR // it's get notified via HMR
ReactDOM.unmountComponentAtNode(appContainer) ReactDOM.unmountComponentAtNode(appContainer)
renderReactElement(<ErrorDebugComponent error={err} />, errorContainer) renderReactElement(<DevErrorOverlay error={err} />, errorContainer)
return return
} }
@ -168,7 +166,7 @@ export async function renderError (props) {
await doRender({...props, err, Component: ErrorComponent}) await doRender({...props, err, Component: ErrorComponent})
} }
async function doRender ({ Component, props, hash, err, emitter: emitterProp = emitter }) { async function doRender ({ App, Component, props, hash, err, emitter: emitterProp = emitter }) {
// Usual getInitialProps fetching is handled in next/router // Usual getInitialProps fetching is handled in next/router
// this is for when ErrorComponent gets replaced by Component by HMR // this is for when ErrorComponent gets replaced by Component by HMR
if (!props && Component && if (!props && Component &&
@ -190,14 +188,24 @@ async function doRender ({ Component, props, hash, err, emitter: emitterProp = e
// We need to clear any existing runtime error messages // We need to clear any existing runtime error messages
ReactDOM.unmountComponentAtNode(errorContainer) ReactDOM.unmountComponentAtNode(errorContainer)
// In development we render react-hot-loader's wrapper component let onError = null
if (HotAppContainer) {
renderReactElement(<HotAppContainer errorReporter={ErrorDebugComponent} warnings={false}> if (process.env.NODE_ENV !== 'development') {
<App {...appProps} /> onError = async (error, errorInfo) => {
</HotAppContainer>, appContainer) try {
} else { await renderError({App, err: error, errorInfo})
renderReactElement(<App {...appProps} />, appContainer) } catch (err) {
console.error('Error while rendering error page: ', err)
} }
}
}
// In development we render a wrapper component that catches runtime errors.
renderReactElement((
<ErrorBoundary ErrorReporter={DevErrorOverlay} onError={onError}>
<App {...appProps} />
</ErrorBoundary>
), appContainer)
emitterProp.emit('after-reactdom-render', { Component, ErrorComponent, appProps }) emitterProp.emit('after-reactdom-render', { Component, ErrorComponent, appProps })
} }

View file

@ -1,14 +1,13 @@
import stripAnsi from 'strip-ansi' import stripAnsi from 'strip-ansi'
import initNext, * as next from './' import initNext, * as next from './'
import {ClientDebug} from '../lib/error-debug' import DevErrorOverlay from './dev-error-overlay'
import initOnDemandEntries from './on-demand-entries-client' import initOnDemandEntries from './on-demand-entries-client'
import initWebpackHMR from './webpack-hot-middleware-client' import initWebpackHMR from './webpack-hot-middleware-client'
import {AppContainer as HotAppContainer} from 'react-hot-loader'
import {applySourcemaps} from './source-map-support' import {applySourcemaps} from './source-map-support'
window.next = next window.next = next
initNext({ HotAppContainer, ErrorDebugComponent: ClientDebug, applySourcemaps, stripAnsi }) initNext({ DevErrorOverlay, applySourcemaps, stripAnsi })
.then((emitter) => { .then((emitter) => {
initOnDemandEntries() initOnDemandEntries()
initWebpackHMR() initWebpackHMR()

View file

@ -0,0 +1,53 @@
// flow-typed signature: 729d832efcac0a21ab881042caf78e1e
// flow-typed version: <<STUB>>/react-lifecycles-compat_v3.0.4/flow_v0.73.0
/**
* This is an autogenerated libdef stub for:
*
* 'react-lifecycles-compat'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'react-lifecycles-compat' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'react-lifecycles-compat/react-lifecycles-compat.cjs' {
declare module.exports: any;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat.es' {
declare module.exports: any;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat' {
declare module.exports: any;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat.min' {
declare module.exports: any;
}
// Filename aliases
declare module 'react-lifecycles-compat/react-lifecycles-compat.cjs.js' {
declare module.exports: $Exports<'react-lifecycles-compat/react-lifecycles-compat.cjs'>;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat.es.js' {
declare module.exports: $Exports<'react-lifecycles-compat/react-lifecycles-compat.es'>;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat.js' {
declare module.exports: $Exports<'react-lifecycles-compat/react-lifecycles-compat'>;
}
declare module 'react-lifecycles-compat/react-lifecycles-compat.min.js' {
declare module.exports: $Exports<'react-lifecycles-compat/react-lifecycles-compat.min'>;
}

123
flow-typed/npm/source-map_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,123 @@
// flow-typed signature: 4307ae4d07743816402f6fe06ed629ad
// flow-typed version: <<STUB>>/source-map_v0.5.7/flow_v0.73.0
/**
* This is an autogenerated libdef stub for:
*
* 'source-map'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'source-map' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'source-map/dist/source-map.debug' {
declare module.exports: any;
}
declare module 'source-map/dist/source-map' {
declare module.exports: any;
}
declare module 'source-map/dist/source-map.min' {
declare module.exports: any;
}
declare module 'source-map/lib/array-set' {
declare module.exports: any;
}
declare module 'source-map/lib/base64-vlq' {
declare module.exports: any;
}
declare module 'source-map/lib/base64' {
declare module.exports: any;
}
declare module 'source-map/lib/binary-search' {
declare module.exports: any;
}
declare module 'source-map/lib/mapping-list' {
declare module.exports: any;
}
declare module 'source-map/lib/quick-sort' {
declare module.exports: any;
}
declare module 'source-map/lib/source-map-consumer' {
declare module.exports: any;
}
declare module 'source-map/lib/source-map-generator' {
declare module.exports: any;
}
declare module 'source-map/lib/source-node' {
declare module.exports: any;
}
declare module 'source-map/lib/util' {
declare module.exports: any;
}
declare module 'source-map/source-map' {
declare module.exports: any;
}
// Filename aliases
declare module 'source-map/dist/source-map.debug.js' {
declare module.exports: $Exports<'source-map/dist/source-map.debug'>;
}
declare module 'source-map/dist/source-map.js' {
declare module.exports: $Exports<'source-map/dist/source-map'>;
}
declare module 'source-map/dist/source-map.min.js' {
declare module.exports: $Exports<'source-map/dist/source-map.min'>;
}
declare module 'source-map/lib/array-set.js' {
declare module.exports: $Exports<'source-map/lib/array-set'>;
}
declare module 'source-map/lib/base64-vlq.js' {
declare module.exports: $Exports<'source-map/lib/base64-vlq'>;
}
declare module 'source-map/lib/base64.js' {
declare module.exports: $Exports<'source-map/lib/base64'>;
}
declare module 'source-map/lib/binary-search.js' {
declare module.exports: $Exports<'source-map/lib/binary-search'>;
}
declare module 'source-map/lib/mapping-list.js' {
declare module.exports: $Exports<'source-map/lib/mapping-list'>;
}
declare module 'source-map/lib/quick-sort.js' {
declare module.exports: $Exports<'source-map/lib/quick-sort'>;
}
declare module 'source-map/lib/source-map-consumer.js' {
declare module.exports: $Exports<'source-map/lib/source-map-consumer'>;
}
declare module 'source-map/lib/source-map-generator.js' {
declare module.exports: $Exports<'source-map/lib/source-map-generator'>;
}
declare module 'source-map/lib/source-node.js' {
declare module.exports: $Exports<'source-map/lib/source-node'>;
}
declare module 'source-map/lib/util.js' {
declare module.exports: $Exports<'source-map/lib/util'>;
}
declare module 'source-map/source-map.js' {
declare module.exports: $Exports<'source-map/source-map'>;
}

60
flow-typed/npm/unfetch_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,60 @@
// flow-typed signature: a652d8adeb137f15eeb79e87d8238710
// flow-typed version: <<STUB>>/unfetch_v3.0.0/flow_v0.73.0
/**
* This is an autogenerated libdef stub for:
*
* 'unfetch'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'unfetch' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'unfetch/dist/unfetch.es' {
declare module.exports: any;
}
declare module 'unfetch/dist/unfetch' {
declare module.exports: any;
}
declare module 'unfetch/dist/unfetch.umd' {
declare module.exports: any;
}
declare module 'unfetch/polyfill' {
declare module.exports: any;
}
declare module 'unfetch/src/index' {
declare module.exports: any;
}
// Filename aliases
declare module 'unfetch/dist/unfetch.es.js' {
declare module.exports: $Exports<'unfetch/dist/unfetch.es'>;
}
declare module 'unfetch/dist/unfetch.js' {
declare module.exports: $Exports<'unfetch/dist/unfetch'>;
}
declare module 'unfetch/dist/unfetch.umd.js' {
declare module.exports: $Exports<'unfetch/dist/unfetch.umd'>;
}
declare module 'unfetch/polyfill.js' {
declare module.exports: $Exports<'unfetch/polyfill'>;
}
declare module 'unfetch/src/index.js' {
declare module.exports: $Exports<'unfetch/src/index'>;
}

102
flow-typed/npm/webpack-sources_vx.x.x.js vendored Normal file
View file

@ -0,0 +1,102 @@
// flow-typed signature: d41ce38862b325831cb20e57893195bc
// flow-typed version: <<STUB>>/webpack-sources_v1.1.0/flow_v0.73.0
/**
* This is an autogenerated libdef stub for:
*
* 'webpack-sources'
*
* Fill this stub out by replacing all the `any` types.
*
* Once filled out, we encourage you to share your work with the
* community by sending a pull request to:
* https://github.com/flowtype/flow-typed
*/
declare module 'webpack-sources' {
declare module.exports: any;
}
/**
* We include stubs for each file inside this npm package in case you need to
* require those files directly. Feel free to delete any files that aren't
* needed.
*/
declare module 'webpack-sources/lib/CachedSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/ConcatSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/index' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/LineToLineMappedSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/OriginalSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/PrefixSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/RawSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/ReplaceSource' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/Source' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/SourceAndMapMixin' {
declare module.exports: any;
}
declare module 'webpack-sources/lib/SourceMapSource' {
declare module.exports: any;
}
// Filename aliases
declare module 'webpack-sources/lib/CachedSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/CachedSource'>;
}
declare module 'webpack-sources/lib/ConcatSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/ConcatSource'>;
}
declare module 'webpack-sources/lib/index.js' {
declare module.exports: $Exports<'webpack-sources/lib/index'>;
}
declare module 'webpack-sources/lib/LineToLineMappedSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/LineToLineMappedSource'>;
}
declare module 'webpack-sources/lib/OriginalSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/OriginalSource'>;
}
declare module 'webpack-sources/lib/PrefixSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/PrefixSource'>;
}
declare module 'webpack-sources/lib/RawSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/RawSource'>;
}
declare module 'webpack-sources/lib/ReplaceSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/ReplaceSource'>;
}
declare module 'webpack-sources/lib/Source.js' {
declare module.exports: $Exports<'webpack-sources/lib/Source'>;
}
declare module 'webpack-sources/lib/SourceAndMapMixin.js' {
declare module.exports: $Exports<'webpack-sources/lib/SourceAndMapMixin'>;
}
declare module 'webpack-sources/lib/SourceMapSource.js' {
declare module.exports: $Exports<'webpack-sources/lib/SourceMapSource'>;
}

View file

@ -27,19 +27,11 @@ export default class App extends Component {
} }
} }
componentDidCatch (err, info) { // Kept here for backwards compatibility.
// To provide clearer stacktraces in error-debug.js in development // When someone ended App they could call `super.componentDidCatch`. This is now deprecated.
// To provide clearer stacktraces in app.js in production componentDidCatch (err) {
err.info = info
if (process.env.NODE_ENV === 'production') {
// In production we render _error.js
window.next.renderError({err})
} else {
// In development we throw the error up to AppContainer from react-hot-loader
throw err throw err
} }
}
render () { render () {
const {router, Component, pageProps} = this.props const {router, Component, pageProps} = this.props

View file

@ -1,43 +1,12 @@
// @flow
import React from 'react' import React from 'react'
import ansiHTML from 'ansi-html' import ansiHTML from 'ansi-html'
import Head from './head' import Head from './head'
import {applySourcemaps} from '../client/source-map-support' import type {ErrorReporterProps} from '../client/error-boundary'
// On the client side the error can come from multiple places for example react-hot-loader or client/index.js // This component is rendered through dev-error-overlay on the client side.
// `componentDidCatch` doesn't support asynchronous execution, so we have to handle sourcemap support here // On the server side it's rendered directly
export class ClientDebug extends React.Component { export default function ErrorDebug ({error, info}: ErrorReporterProps) {
state = {
mappedError: null
}
componentDidMount () {
const {error} = this.props
// If sourcemaps were already applied there is no need to set the state
if (error.sourceMapsApplied) {
return
}
// Since componentDidMount doesn't handle errors we use then/catch here
applySourcemaps(error).then(() => {
this.setState({mappedError: error})
}).catch(console.error)
}
render () {
const {mappedError} = this.state
const {error} = this.props
if (!error.sourceMapsApplied && mappedError === null) {
return <div style={styles.errorDebug}>
<h1 style={styles.heading}>Loading stacktrace...</h1>
</div>
}
return <ErrorDebug error={error} />
}
}
// On the server side the error has sourcemaps already applied, so `ErrorDebug` is rendered directly.
export default function ErrorDebug ({error}) {
const { name, message, module } = error const { name, message, module } = error
return ( return (
<div style={styles.errorDebug}> <div style={styles.errorDebug}>
@ -46,15 +15,15 @@ export default function ErrorDebug ({error}) {
</Head> </Head>
{module ? <h1 style={styles.heading}>Error in {module.rawRequest}</h1> : null} {module ? <h1 style={styles.heading}>Error in {module.rawRequest}</h1> : null}
{ {
name === 'ModuleBuildError' name === 'ModuleBuildError' && message
? <pre style={styles.stack} dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} /> ? <pre style={styles.stack} dangerouslySetInnerHTML={{ __html: ansiHTML(encodeHtml(message)) }} />
: <StackTrace error={error} /> : <StackTrace error={error} info={info} />
} }
</div> </div>
) )
} }
const StackTrace = ({ error: { name, message, stack, info } }) => ( const StackTrace = ({ error: { name, message, stack }, info }: ErrorReporterProps) => (
<div> <div>
<div style={styles.heading}>{message || name}</div> <div style={styles.heading}>{message || name}</div>
<pre style={styles.stack}> <pre style={styles.stack}>
@ -66,7 +35,7 @@ const StackTrace = ({ error: { name, message, stack, info } }) => (
</div> </div>
) )
const styles = { export const styles = {
errorDebug: { errorDebug: {
background: '#0e0d0d', background: '#0e0d0d',
boxSizing: 'border-box', boxSizing: 'border-box',

View file

@ -28,12 +28,13 @@ export default class Router {
this.components[this.route] = { Component, props: initialProps, err } this.components[this.route] = { Component, props: initialProps, err }
} }
this.components['/_app'] = { Component: App }
// Handling Router Events // Handling Router Events
this.events = new EventEmitter() this.events = new EventEmitter()
this.pageLoader = pageLoader this.pageLoader = pageLoader
this.prefetchQueue = new PQueue({ concurrency: 2 }) this.prefetchQueue = new PQueue({ concurrency: 2 })
this.App = App
this.ErrorComponent = ErrorComponent this.ErrorComponent = ErrorComponent
this.pathname = pathname this.pathname = pathname
this.query = query this.query = query
@ -352,8 +353,9 @@ export default class Router {
let cancelled = false let cancelled = false
const cancel = () => { cancelled = true } const cancel = () => { cancelled = true }
this.componentLoadCancel = cancel this.componentLoadCancel = cancel
const {Component: App} = this.components['/_app']
const props = await loadGetInitialProps(this.App, {Component, router: this, ctx}) const props = await loadGetInitialProps(App, {Component, router: this, ctx})
if (cancel === this.componentLoadCancel) { if (cancel === this.componentLoadCancel) {
this.componentLoadCancel = null this.componentLoadCancel = null
@ -381,7 +383,8 @@ export default class Router {
} }
notify (data) { notify (data) {
this.subscriptions.forEach((fn) => fn(data)) const {Component: App} = this.components['/_app']
this.subscriptions.forEach((fn) => fn({...data, App}))
} }
subscribe (fn) { subscribe (fn) {

View file

@ -34,9 +34,10 @@
"testonly": "cross-env NODE_PATH=test/lib jest \\.test.js", "testonly": "cross-env NODE_PATH=test/lib jest \\.test.js",
"posttestonly": "taskr posttest", "posttestonly": "taskr posttest",
"testall": "npm run testonly -- --coverage --forceExit --runInBand --verbose --bail", "testall": "npm run testonly -- --coverage --forceExit --runInBand --verbose --bail",
"pretest": "npm run lint", "pretest": "npm run lint && npm run flow",
"test": "cross-env npm run testall || npm run testall", "test": "cross-env npm run testall || npm run testall",
"coveralls": "nyc --instrument=false --source-map=false report --temp-directory=./coverage --reporter=text-lcov | coveralls", "coveralls": "nyc --instrument=false --source-map=false report --temp-directory=./coverage --reporter=text-lcov | coveralls",
"flow": "flow check",
"lint": "standard 'bin/*' 'client/**/*.js' 'examples/**/*.js' 'lib/**/*.js' 'pages/**/*.js' 'server/**/*.js' 'test/**/*.js'", "lint": "standard 'bin/*' 'client/**/*.js' 'examples/**/*.js' 'lib/**/*.js' 'pages/**/*.js' 'server/**/*.js' 'test/**/*.js'",
"prepublish": "npm run release", "prepublish": "npm run release",
"precommit": "lint-staged" "precommit": "lint-staged"
@ -88,6 +89,7 @@
"prop-types": "15.6.0", "prop-types": "15.6.0",
"prop-types-exact": "1.1.1", "prop-types-exact": "1.1.1",
"react-hot-loader": "4.1.3", "react-hot-loader": "4.1.3",
"react-lifecycles-compat": "3.0.4",
"recursive-copy": "2.0.6", "recursive-copy": "2.0.6",
"resolve": "1.5.0", "resolve": "1.5.0",
"send": "0.16.1", "send": "0.16.1",
@ -126,6 +128,7 @@
"cross-env": "5.0.5", "cross-env": "5.0.5",
"express": "4.15.5", "express": "4.15.5",
"fkill": "5.1.0", "fkill": "5.1.0",
"flow-bin": "0.73.0",
"get-port": "3.2.0", "get-port": "3.2.0",
"husky": "0.14.3", "husky": "0.14.3",
"jest-cli": "21.2.0", "jest-cli": "21.2.0",
@ -135,8 +138,8 @@
"node-fetch": "1.7.3", "node-fetch": "1.7.3",
"node-notifier": "5.1.2", "node-notifier": "5.1.2",
"nyc": "11.2.1", "nyc": "11.2.1",
"react": "16.2.0", "react": "16.4.0",
"react-dom": "16.2.0", "react-dom": "16.4.0",
"rimraf": "2.6.2", "rimraf": "2.6.2",
"standard": "11.0.1", "standard": "11.0.1",
"taskr": "1.1.0", "taskr": "1.1.0",

View file

@ -2,7 +2,6 @@ import babelLoader from 'babel-loader'
module.exports = babelLoader.custom(babel => { module.exports = babelLoader.custom(babel => {
const presetItem = babel.createConfigItem(require('../babel/preset'), {type: 'preset'}) const presetItem = babel.createConfigItem(require('../babel/preset'), {type: 'preset'})
const hotLoaderItem = babel.createConfigItem(require('react-hot-loader/babel'), {type: 'plugin'})
const reactJsxSourceItem = babel.createConfigItem(require('@babel/plugin-transform-react-jsx-source'), {type: 'plugin'}) const reactJsxSourceItem = babel.createConfigItem(require('@babel/plugin-transform-react-jsx-source'), {type: 'plugin'})
const configs = new Set() const configs = new Set()
@ -38,7 +37,6 @@ module.exports = babelLoader.custom(babel => {
options.plugins = [ options.plugins = [
...options.plugins, ...options.plugins,
dev && !isServer && hotLoaderItem,
dev && reactJsxSourceItem dev && reactJsxSourceItem
].filter(Boolean) ].filter(Boolean)

View file

@ -177,7 +177,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer
// required not to cache removed files // required not to cache removed files
useHashIndex: false useHashIndex: false
}), }),
!dev && new webpack.IgnorePlugin(/react-hot-loader/),
!isServer && !dev && new UglifyJSPlugin({ !isServer && !dev && new UglifyJSPlugin({
exclude: /react\.js/, exclude: /react\.js/,
parallel: true, parallel: true,

View file

@ -3166,6 +3166,10 @@ flatten@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flow-bin@0.73.0:
version "0.73.0"
resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.73.0.tgz#da1b90a02b0ef9c439f068c2fc14968db83be425"
flush-write-stream@^1.0.0: flush-write-stream@^1.0.0:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.0.3.tgz#c5d586ef38af6097650b49bc41b55fabb19f35bd"
@ -6132,9 +6136,9 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
react-dom@16.2.0: react-dom@16.4.0:
version "16.2.0" version "16.4.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e"
dependencies: dependencies:
fbjs "^0.8.16" fbjs "^0.8.16"
loose-envify "^1.1.0" loose-envify "^1.1.0"
@ -6152,13 +6156,17 @@ react-hot-loader@4.1.3:
react-lifecycles-compat "^3.0.2" react-lifecycles-compat "^3.0.2"
shallowequal "^1.0.2" shallowequal "^1.0.2"
react-lifecycles-compat@3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
react-lifecycles-compat@^3.0.2: react-lifecycles-compat@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff"
react@16.2.0: react@16.4.0:
version "16.2.0" version "16.4.0"
resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585"
dependencies: dependencies:
fbjs "^0.8.16" fbjs "^0.8.16"
loose-envify "^1.1.0" loose-envify "^1.1.0"