From 86d01706a67cee5c80796974d04c1e11cdff453a Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 31 May 2018 11:47:29 +0200 Subject: [PATCH] Remove react-hot-loader (#4500) Fixes #4494 --- .flowconfig | 3 +- appveyor.yml | 2 +- client/dev-error-overlay.js | 41 ++++++ client/error-boundary.js | 66 ++++++++++ client/index.js | 48 ++++--- client/next-dev.js | 5 +- .../npm/react-lifecycles-compat_vx.x.x.js | 53 ++++++++ flow-typed/npm/source-map_vx.x.x.js | 123 ++++++++++++++++++ flow-typed/npm/unfetch_vx.x.x.js | 60 +++++++++ flow-typed/npm/webpack-sources_vx.x.x.js | 102 +++++++++++++++ lib/app.js | 16 +-- lib/error-debug.js | 49 ++----- lib/router/router.js | 9 +- package.json | 9 +- server/build/loaders/next-babel-loader.js | 2 - server/build/webpack.js | 1 - yarn.lock | 20 ++- 17 files changed, 517 insertions(+), 92 deletions(-) create mode 100644 client/dev-error-overlay.js create mode 100644 client/error-boundary.js create mode 100644 flow-typed/npm/react-lifecycles-compat_vx.x.x.js create mode 100644 flow-typed/npm/source-map_vx.x.x.js create mode 100644 flow-typed/npm/unfetch_vx.x.x.js create mode 100644 flow-typed/npm/webpack-sources_vx.x.x.js diff --git a/.flowconfig b/.flowconfig index 581592b12a..4d38b2dac4 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,2 +1,3 @@ [ignore] -/examples/.* \ No newline at end of file +/examples/.* +/.*.json \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index 995d73984a..9b6ee2d987 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ install: # Install Google Chrome for e2e testing - choco install --ignore-checksums googlechrome # 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 - npm install diff --git a/client/dev-error-overlay.js b/client/dev-error-overlay.js new file mode 100644 index 0000000000..b85867c019 --- /dev/null +++ b/client/dev-error-overlay.js @@ -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 { + 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
+

Loading stacktrace...

+
+ } + + return + } +} + +export default DevErrorOverlay diff --git a/client/error-boundary.js b/client/error-boundary.js new file mode 100644 index 0000000000..4dc8cf73f1 --- /dev/null +++ b/client/error-boundary.js @@ -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 + +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 { + 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 + } + + 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 diff --git a/client/index.js b/client/index.js index 942a207926..57d3bdfce5 100644 --- a/client/index.js +++ b/client/index.js @@ -7,6 +7,7 @@ import { loadGetInitialProps, getURL } from '../lib/utils' import PageLoader from '../lib/page-loader' import * as asset from '../lib/asset' import * as envConfig from '../lib/runtime-config' +import ErrorBoundary from './error-boundary' // Polyfill Promise globally // This is needed because Webpack2's dynamic loading(common chunks) code @@ -66,8 +67,7 @@ const errorContainer = document.getElementById('__next-error') let lastAppProps export let router export let ErrorComponent -let HotAppContainer -let ErrorDebugComponent +let DevErrorOverlay let Component let App let stripAnsi = (s) => s @@ -76,8 +76,7 @@ let applySourcemaps = (e) => e export const emitter = new EventEmitter() export default async ({ - HotAppContainer: passedHotAppContainer, - ErrorDebugComponent: passedDebugComponent, + DevErrorOverlay: passedDevErrorOverlay, stripAnsi: passedStripAnsi, applySourcemaps: passedApplySourcemaps } = {}) => { @@ -88,8 +87,7 @@ export default async ({ stripAnsi = passedStripAnsi || stripAnsi applySourcemaps = passedApplySourcemaps || applySourcemaps - HotAppContainer = passedHotAppContainer - ErrorDebugComponent = passedDebugComponent + DevErrorOverlay = passedDevErrorOverlay ErrorComponent = await pageLoader.loadPage('/_error') App = await pageLoader.loadPage('/_app') @@ -115,12 +113,12 @@ export default async ({ err: initialErr }) - router.subscribe(({ Component, props, hash, err }) => { - render({ Component, props, err, hash, emitter }) + router.subscribe(({ App, Component, props, hash, err }) => { + render({ App, Component, props, err, hash, emitter }) }) const hash = location.hash.substring(1) - render({ Component, props, hash, err: initialErr, emitter }) + render({ App, Component, props, hash, err: initialErr, emitter }) return emitter } @@ -143,14 +141,14 @@ export async function render (props) { // 404 and 500 errors are special kind of errors // and they are still handle via the main render method. export async function renderError (props) { - const {err} = props + const {err, errorInfo} = props // In development we apply sourcemaps to the error if (process.env.NODE_ENV !== 'production') { 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) 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 // it's get notified via HMR ReactDOM.unmountComponentAtNode(appContainer) - renderReactElement(, errorContainer) + renderReactElement(, errorContainer) return } @@ -168,7 +166,7 @@ export async function renderError (props) { 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 // this is for when ErrorComponent gets replaced by Component by HMR if (!props && Component && @@ -190,15 +188,25 @@ async function doRender ({ Component, props, hash, err, emitter: emitterProp = e // We need to clear any existing runtime error messages ReactDOM.unmountComponentAtNode(errorContainer) - // In development we render react-hot-loader's wrapper component - if (HotAppContainer) { - renderReactElement( - - , appContainer) - } else { - renderReactElement(, appContainer) + let onError = null + + if (process.env.NODE_ENV !== 'development') { + onError = async (error, errorInfo) => { + try { + await renderError({App, err: error, errorInfo}) + } catch (err) { + console.error('Error while rendering error page: ', err) + } + } } + // In development we render a wrapper component that catches runtime errors. + renderReactElement(( + + + + ), appContainer) + emitterProp.emit('after-reactdom-render', { Component, ErrorComponent, appProps }) } diff --git a/client/next-dev.js b/client/next-dev.js index 07e86f79d0..5e1299b813 100644 --- a/client/next-dev.js +++ b/client/next-dev.js @@ -1,14 +1,13 @@ import stripAnsi from 'strip-ansi' 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 initWebpackHMR from './webpack-hot-middleware-client' -import {AppContainer as HotAppContainer} from 'react-hot-loader' import {applySourcemaps} from './source-map-support' window.next = next -initNext({ HotAppContainer, ErrorDebugComponent: ClientDebug, applySourcemaps, stripAnsi }) +initNext({ DevErrorOverlay, applySourcemaps, stripAnsi }) .then((emitter) => { initOnDemandEntries() initWebpackHMR() diff --git a/flow-typed/npm/react-lifecycles-compat_vx.x.x.js b/flow-typed/npm/react-lifecycles-compat_vx.x.x.js new file mode 100644 index 0000000000..6b3f50d96c --- /dev/null +++ b/flow-typed/npm/react-lifecycles-compat_vx.x.x.js @@ -0,0 +1,53 @@ +// flow-typed signature: 729d832efcac0a21ab881042caf78e1e +// flow-typed version: <>/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'>; +} diff --git a/flow-typed/npm/source-map_vx.x.x.js b/flow-typed/npm/source-map_vx.x.x.js new file mode 100644 index 0000000000..16fbcdc456 --- /dev/null +++ b/flow-typed/npm/source-map_vx.x.x.js @@ -0,0 +1,123 @@ +// flow-typed signature: 4307ae4d07743816402f6fe06ed629ad +// flow-typed version: <>/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'>; +} diff --git a/flow-typed/npm/unfetch_vx.x.x.js b/flow-typed/npm/unfetch_vx.x.x.js new file mode 100644 index 0000000000..2c937eae22 --- /dev/null +++ b/flow-typed/npm/unfetch_vx.x.x.js @@ -0,0 +1,60 @@ +// flow-typed signature: a652d8adeb137f15eeb79e87d8238710 +// flow-typed version: <>/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'>; +} diff --git a/flow-typed/npm/webpack-sources_vx.x.x.js b/flow-typed/npm/webpack-sources_vx.x.x.js new file mode 100644 index 0000000000..cbe47577b9 --- /dev/null +++ b/flow-typed/npm/webpack-sources_vx.x.x.js @@ -0,0 +1,102 @@ +// flow-typed signature: d41ce38862b325831cb20e57893195bc +// flow-typed version: <>/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'>; +} diff --git a/lib/app.js b/lib/app.js index 7cecba362e..fc1de5f250 100644 --- a/lib/app.js +++ b/lib/app.js @@ -27,18 +27,10 @@ export default class App extends Component { } } - componentDidCatch (err, info) { - // To provide clearer stacktraces in error-debug.js in development - // To provide clearer stacktraces in app.js in production - 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 - } + // Kept here for backwards compatibility. + // When someone ended App they could call `super.componentDidCatch`. This is now deprecated. + componentDidCatch (err) { + throw err } render () { diff --git a/lib/error-debug.js b/lib/error-debug.js index a3ca80e19d..808b02241c 100644 --- a/lib/error-debug.js +++ b/lib/error-debug.js @@ -1,43 +1,12 @@ +// @flow import React from 'react' import ansiHTML from 'ansi-html' 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 -// `componentDidCatch` doesn't support asynchronous execution, so we have to handle sourcemap support here -export class ClientDebug extends React.Component { - 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
-

Loading stacktrace...

-
- } - - return - } -} - -// On the server side the error has sourcemaps already applied, so `ErrorDebug` is rendered directly. -export default function ErrorDebug ({error}) { +// This component is rendered through dev-error-overlay on the client side. +// On the server side it's rendered directly +export default function ErrorDebug ({error, info}: ErrorReporterProps) { const { name, message, module } = error return (
@@ -46,15 +15,15 @@ export default function ErrorDebug ({error}) { {module ?

Error in {module.rawRequest}

: null} { - name === 'ModuleBuildError' + name === 'ModuleBuildError' && message ?
-          : 
+          : 
       }
     
) } -const StackTrace = ({ error: { name, message, stack, info } }) => ( +const StackTrace = ({ error: { name, message, stack }, info }: ErrorReporterProps) => (
{message || name}
@@ -66,7 +35,7 @@ const StackTrace = ({ error: { name, message, stack, info } }) => (
   
) -const styles = { +export const styles = { errorDebug: { background: '#0e0d0d', boxSizing: 'border-box', diff --git a/lib/router/router.js b/lib/router/router.js index 15e456a46e..8cd183eca8 100644 --- a/lib/router/router.js +++ b/lib/router/router.js @@ -28,12 +28,13 @@ export default class Router { this.components[this.route] = { Component, props: initialProps, err } } + this.components['/_app'] = { Component: App } + // Handling Router Events this.events = new EventEmitter() this.pageLoader = pageLoader this.prefetchQueue = new PQueue({ concurrency: 2 }) - this.App = App this.ErrorComponent = ErrorComponent this.pathname = pathname this.query = query @@ -352,8 +353,9 @@ export default class Router { let cancelled = false const cancel = () => { cancelled = true } 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) { this.componentLoadCancel = null @@ -381,7 +383,8 @@ export default class Router { } notify (data) { - this.subscriptions.forEach((fn) => fn(data)) + const {Component: App} = this.components['/_app'] + this.subscriptions.forEach((fn) => fn({...data, App})) } subscribe (fn) { diff --git a/package.json b/package.json index fa33c7a65d..f9261f047c 100644 --- a/package.json +++ b/package.json @@ -34,9 +34,10 @@ "testonly": "cross-env NODE_PATH=test/lib jest \\.test.js", "posttestonly": "taskr posttest", "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", "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'", "prepublish": "npm run release", "precommit": "lint-staged" @@ -88,6 +89,7 @@ "prop-types": "15.6.0", "prop-types-exact": "1.1.1", "react-hot-loader": "4.1.3", + "react-lifecycles-compat": "3.0.4", "recursive-copy": "2.0.6", "resolve": "1.5.0", "send": "0.16.1", @@ -126,6 +128,7 @@ "cross-env": "5.0.5", "express": "4.15.5", "fkill": "5.1.0", + "flow-bin": "0.73.0", "get-port": "3.2.0", "husky": "0.14.3", "jest-cli": "21.2.0", @@ -135,8 +138,8 @@ "node-fetch": "1.7.3", "node-notifier": "5.1.2", "nyc": "11.2.1", - "react": "16.2.0", - "react-dom": "16.2.0", + "react": "16.4.0", + "react-dom": "16.4.0", "rimraf": "2.6.2", "standard": "11.0.1", "taskr": "1.1.0", diff --git a/server/build/loaders/next-babel-loader.js b/server/build/loaders/next-babel-loader.js index c468bb7c88..cf2bdda9b4 100644 --- a/server/build/loaders/next-babel-loader.js +++ b/server/build/loaders/next-babel-loader.js @@ -2,7 +2,6 @@ import babelLoader from 'babel-loader' module.exports = babelLoader.custom(babel => { 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 configs = new Set() @@ -38,7 +37,6 @@ module.exports = babelLoader.custom(babel => { options.plugins = [ ...options.plugins, - dev && !isServer && hotLoaderItem, dev && reactJsxSourceItem ].filter(Boolean) diff --git a/server/build/webpack.js b/server/build/webpack.js index 43a9047a05..e85e0dfff4 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -177,7 +177,6 @@ export default async function getBaseWebpackConfig (dir, {dev = false, isServer // required not to cache removed files useHashIndex: false }), - !dev && new webpack.IgnorePlugin(/react-hot-loader/), !isServer && !dev && new UglifyJSPlugin({ exclude: /react\.js/, parallel: true, diff --git a/yarn.lock b/yarn.lock index 54cbff6cc3..ad8ff28dea 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3166,6 +3166,10 @@ flatten@^1.0.2: version "1.0.2" 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: version "1.0.3" 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" strip-json-comments "~2.0.1" -react-dom@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" +react-dom@16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" @@ -6152,13 +6156,17 @@ react-hot-loader@4.1.3: react-lifecycles-compat "^3.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: version "3.0.2" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.2.tgz#7279047275bd727a912e25f734c0559527e84eff" -react@16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" +react@16.4.0: + version "16.4.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.4.0.tgz#402c2db83335336fba1962c08b98c6272617d585" dependencies: fbjs "^0.8.16" loose-envify "^1.1.0" -- GitLab