mirror of
https://github.com/terribleplan/next.js.git
synced 2024-01-19 02:48:18 +00:00
Open editor from error-overlay (minor) (#4979)
This PR adds links to the [react-error-overlay](https://www.npmjs.com/package/react-error-overlay). This allows a developer to open a stack trace in its own editor. ![codelinking](https://user-images.githubusercontent.com/1265681/44278860-a63e0a80-a24f-11e8-9c69-c5365c026c58.gif) Closes #4813
This commit is contained in:
parent
0dd2b2aa74
commit
11816537c3
|
@ -6,9 +6,9 @@
|
||||||
import {getEventSourceWrapper} from './eventsource'
|
import {getEventSourceWrapper} from './eventsource'
|
||||||
import formatWebpackMessages from './format-webpack-messages'
|
import formatWebpackMessages from './format-webpack-messages'
|
||||||
import * as ErrorOverlay from 'react-error-overlay'
|
import * as ErrorOverlay from 'react-error-overlay'
|
||||||
// import url from 'url'
|
|
||||||
import stripAnsi from 'strip-ansi'
|
import stripAnsi from 'strip-ansi'
|
||||||
import {rewriteStacktrace} from '../source-map-support'
|
import {rewriteStacktrace} from '../source-map-support'
|
||||||
|
import fetch from 'unfetch'
|
||||||
|
|
||||||
const {
|
const {
|
||||||
distDir
|
distDir
|
||||||
|
@ -30,6 +30,16 @@ const {
|
||||||
let hadRuntimeError = false
|
let hadRuntimeError = false
|
||||||
let customHmrEventHandler
|
let customHmrEventHandler
|
||||||
export default function connect (options) {
|
export default function connect (options) {
|
||||||
|
// Open stack traces in an editor.
|
||||||
|
ErrorOverlay.setEditorHandler(function editorHandler ({ fileName, lineNumber, colNumber }) {
|
||||||
|
fetch(
|
||||||
|
'/_next/development/open-stack-frame-in-editor' +
|
||||||
|
`?fileName=${window.encodeURIComponent(fileName)}` +
|
||||||
|
`&lineNumber=${lineNumber || 1}` +
|
||||||
|
`&colNumber=${colNumber || 1}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// We need to keep track of if there has been a runtime error.
|
// We need to keep track of if there has been a runtime error.
|
||||||
// Essentially, we cannot guarantee application state was not corrupted by the
|
// Essentially, we cannot guarantee application state was not corrupted by the
|
||||||
// runtime error. To prevent confusing behavior, we forcibly reload the entire
|
// runtime error. To prevent confusing behavior, we forcibly reload the entire
|
||||||
|
|
|
@ -87,6 +87,7 @@
|
||||||
"htmlescape": "1.1.1",
|
"htmlescape": "1.1.1",
|
||||||
"http-errors": "1.6.2",
|
"http-errors": "1.6.2",
|
||||||
"http-status": "1.0.1",
|
"http-status": "1.0.1",
|
||||||
|
"launch-editor": "2.2.1",
|
||||||
"loader-utils": "1.1.0",
|
"loader-utils": "1.1.0",
|
||||||
"minimist": "1.2.0",
|
"minimist": "1.2.0",
|
||||||
"mkdirp-then": "1.2.0",
|
"mkdirp-then": "1.2.0",
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { join, relative, sep, normalize } from 'path'
|
import { join, relative, sep, normalize } from 'path'
|
||||||
import WebpackDevMiddleware from 'webpack-dev-middleware'
|
import WebpackDevMiddleware from 'webpack-dev-middleware'
|
||||||
import WebpackHotMiddleware from 'webpack-hot-middleware'
|
import WebpackHotMiddleware from 'webpack-hot-middleware'
|
||||||
|
import errorOverlayMiddleware from './lib/error-overlay-middleware'
|
||||||
import del from 'del'
|
import del from 'del'
|
||||||
import onDemandEntryHandler, {normalizePage} from './on-demand-entry-handler'
|
import onDemandEntryHandler, {normalizePage} from './on-demand-entry-handler'
|
||||||
import webpack from 'webpack'
|
import webpack from 'webpack'
|
||||||
|
@ -186,6 +187,7 @@ export default class HotReloader {
|
||||||
this.middlewares = [
|
this.middlewares = [
|
||||||
webpackDevMiddleware,
|
webpackDevMiddleware,
|
||||||
webpackHotMiddleware,
|
webpackHotMiddleware,
|
||||||
|
errorOverlayMiddleware,
|
||||||
onDemandEntries.middleware()
|
onDemandEntries.middleware()
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
14
server/lib/error-overlay-middleware.js
Normal file
14
server/lib/error-overlay-middleware.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import url from 'url'
|
||||||
|
import launchEditor from 'launch-editor'
|
||||||
|
|
||||||
|
export default function errorOverlayMiddleware (req, res, next) {
|
||||||
|
if (req.url.startsWith('/_next/development/open-stack-frame-in-editor')) {
|
||||||
|
const query = url.parse(req.url, true).query
|
||||||
|
const lineNumber = parseInt(query.lineNumber, 10) || 1
|
||||||
|
const colNumber = parseInt(query.colNumber, 10) || 1
|
||||||
|
launchEditor(`${query.fileName}:${lineNumber}:${colNumber}`)
|
||||||
|
res.end()
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,35 @@ import { check, File, waitFor, getReactErrorOverlayContent } from 'next-test-uti
|
||||||
|
|
||||||
export default (context, render) => {
|
export default (context, render) => {
|
||||||
describe('Error Recovery', () => {
|
describe('Error Recovery', () => {
|
||||||
|
it('should have installed the react-overlay-editor editor handler', async () => {
|
||||||
|
let browser
|
||||||
|
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
||||||
|
aboutPage.replace('</div>', 'div')
|
||||||
|
|
||||||
|
try {
|
||||||
|
browser = await webdriver(context.appPort, '/hmr/about')
|
||||||
|
|
||||||
|
// Wait for react-error-overlay
|
||||||
|
await browser.waitForElementByCss('iframe', 2000)
|
||||||
|
|
||||||
|
// react-error-overlay uses the following inline style if an editorHandler is installed
|
||||||
|
expect(await getReactErrorOverlayContent(browser)).toMatch(/style="cursor: pointer;"/)
|
||||||
|
|
||||||
|
aboutPage.restore()
|
||||||
|
|
||||||
|
await check(
|
||||||
|
() => browser.elementByCss('body').text(),
|
||||||
|
/This is the about page/
|
||||||
|
)
|
||||||
|
} finally {
|
||||||
|
aboutPage.restore()
|
||||||
|
|
||||||
|
if (browser) {
|
||||||
|
browser.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it('should detect syntax errors and recover', async () => {
|
it('should detect syntax errors and recover', async () => {
|
||||||
let browser
|
let browser
|
||||||
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
const aboutPage = new File(join(__dirname, '../', 'pages', 'hmr', 'about.js'))
|
||||||
|
|
|
@ -7,7 +7,7 @@ describe('loadGetInitialProps', () => {
|
||||||
getInitialProps () {}
|
getInitialProps () {}
|
||||||
}
|
}
|
||||||
const rejectPromise = loadGetInitialProps(TestComponent, {})
|
const rejectPromise = loadGetInitialProps(TestComponent, {})
|
||||||
const error = new Error('"TestComponent.getInitialProps()" is defined as an instance method - visit https://err.sh/zeit/next.js/get-inital-props-as-an-instance-method for more information.')
|
const error = new Error('"TestComponent.getInitialProps()" is defined as an instance method - visit https://err.sh/zeit/next.js/get-initial-props-as-an-instance-method for more information.')
|
||||||
return expect(rejectPromise).rejects.toEqual(error)
|
return expect(rejectPromise).rejects.toEqual(error)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
30
yarn.lock
30
yarn.lock
|
@ -1074,6 +1074,10 @@ array-equal@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
||||||
|
|
||||||
|
array-filter@~0.0.0:
|
||||||
|
version "0.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
|
||||||
|
|
||||||
array-find-index@^1.0.1:
|
array-find-index@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
|
||||||
|
@ -1089,6 +1093,14 @@ array-includes@^3.0.3:
|
||||||
define-properties "^1.1.2"
|
define-properties "^1.1.2"
|
||||||
es-abstract "^1.7.0"
|
es-abstract "^1.7.0"
|
||||||
|
|
||||||
|
array-map@~0.0.0:
|
||||||
|
version "0.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
|
||||||
|
|
||||||
|
array-reduce@~0.0.0:
|
||||||
|
version "0.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
|
||||||
|
|
||||||
array-union@^1.0.1:
|
array-union@^1.0.1:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
|
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
|
||||||
|
@ -1778,7 +1790,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
|
||||||
strip-ansi "^3.0.0"
|
strip-ansi "^3.0.0"
|
||||||
supports-color "^2.0.0"
|
supports-color "^2.0.0"
|
||||||
|
|
||||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.2, chalk@^2.4.0, chalk@^2.4.1:
|
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.0, chalk@^2.4.1:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4693,6 +4705,13 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
||||||
version "6.0.2"
|
version "6.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||||
|
|
||||||
|
launch-editor@2.2.1:
|
||||||
|
version "2.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.2.1.tgz#871b5a3ee39d6680fcc26d37930b6eeda89db0ca"
|
||||||
|
dependencies:
|
||||||
|
chalk "^2.3.0"
|
||||||
|
shell-quote "^1.6.1"
|
||||||
|
|
||||||
lazy-cache@^0.2.3:
|
lazy-cache@^0.2.3:
|
||||||
version "0.2.7"
|
version "0.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
|
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65"
|
||||||
|
@ -7058,6 +7077,15 @@ shebang-regex@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
|
||||||
|
|
||||||
|
shell-quote@^1.6.1:
|
||||||
|
version "1.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767"
|
||||||
|
dependencies:
|
||||||
|
array-filter "~0.0.0"
|
||||||
|
array-map "~0.0.0"
|
||||||
|
array-reduce "~0.0.0"
|
||||||
|
jsonify "~0.0.0"
|
||||||
|
|
||||||
shellwords@^0.1.0, shellwords@^0.1.1:
|
shellwords@^0.1.0, shellwords@^0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b"
|
||||||
|
|
Loading…
Reference in a new issue