[Fast Refresh] Click to open in editor (#12397)

This commit is contained in:
Joe Haddad 2020-05-01 22:04:03 -04:00 committed by GitHub
parent eab41abada
commit 37e3ec8d17
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 581 additions and 6 deletions

View file

@ -18,7 +18,9 @@
"dependencies": {
"@babel/code-frame": "7.8.3",
"anser": "1.4.9",
"chalk": "4.0.0",
"classnames": "2.2.6",
"shell-quote": "1.7.2",
"source-map": "0.8.0-beta.0",
"stacktrace-parser": "0.1.9",
"strip-ansi": "6.0.0"

View file

@ -40,11 +40,40 @@ export const CodeFrame: React.FC<CodeFrameProps> = function CodeFrame({
})
}, [formattedFrame])
const open = React.useCallback(() => {
const params = new URLSearchParams()
for (const key in stackFrame) {
params.append(key, (stackFrame[key] ?? '').toString())
}
self.fetch(`/__nextjs_launch-editor?${params.toString()}`).then(
() => {},
() => {
// TODO: report error
}
)
}, [stackFrame])
// TODO: make the caret absolute
return (
<div data-nextjs-codeframe>
<p>
{getFrameSource(stackFrame)} @ {stackFrame.methodName}
<p role="link" onClick={open} tabIndex={0}>
<span>
{getFrameSource(stackFrame)} @ {stackFrame.methodName}
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</p>
<hr />
<pre>

View file

@ -33,6 +33,21 @@ const styles = css`
border-bottom-width: 1px;
border-color: var(--color-ansi-fg);
}
[data-nextjs-codeframe] > p {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
[data-nextjs-codeframe] > p:hover {
text-decoration: underline dotted;
}
[data-nextjs-codeframe] > p > svg {
width: auto;
height: 1em;
margin-left: 0.5rem;
}
`
export { styles }

View file

@ -14,10 +14,48 @@ const CallStackFrame: React.FC<{
// TODO: render error or external indicator
const f: StackFrame = frame.originalStackFrame ?? frame.sourceStackFrame
const hasSource = Boolean(frame.originalStackFrame?.file)
const open = React.useCallback(() => {
if (!hasSource) return
const params = new URLSearchParams()
for (const key in f) {
params.append(key, (f[key] ?? '').toString())
}
self.fetch(`/__nextjs_launch-editor?${params.toString()}`).then(
() => {},
() => {
// TODO: report error
}
)
}, [hasSource, f])
return (
<div data-nextjs-call-stack-frame>
<h6>{f.methodName}</h6>
<p>{getFrameSource(f)}</p>
<div
data-has-source={hasSource ? 'true' : undefined}
tabIndex={hasSource ? 0 : undefined}
role={hasSource ? 'link' : undefined}
onClick={open}
>
<span>{getFrameSource(f)}</span>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg>
</div>
</div>
)
}
@ -98,11 +136,31 @@ export const styles = css`
font-family: var(--font-stack-monospace);
color: rgba(25, 25, 25, 1);
}
[data-nextjs-call-stack-frame] > p {
[data-nextjs-call-stack-frame] > div {
display: flex;
align-items: center;
margin-bottom: 1rem;
padding-left: 0.75rem;
font-size: 0.875rem;
color: rgba(25, 25, 25, 0.5);
}
[data-nextjs-call-stack-frame] > div > svg {
width: auto;
height: 0.875rem;
margin-left: 0.5rem;
display: none;
}
[data-nextjs-call-stack-frame] > div[data-has-source] {
cursor: pointer;
}
[data-nextjs-call-stack-frame] > div[data-has-source]:hover {
text-decoration: underline dotted;
}
[data-nextjs-call-stack-frame] > div[data-has-source] > svg {
display: unset;
}
`
export { RuntimeError }

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
import { codeFrameColumns } from '@babel/code-frame'
import { promises as fs } from 'fs'
import { constants as FS, promises as fs } from 'fs'
import { IncomingMessage, ServerResponse } from 'http'
import path from 'path'
import { NullableMappedPosition, SourceMapConsumer } from 'source-map'
@ -7,8 +7,9 @@ import { StackFrame } from 'stacktrace-parser'
import url from 'url'
import webpack from 'webpack'
import { OriginalSource } from 'webpack-sources'
import { launchEditor } from './internal/helpers/launchEditor'
type OverlayMiddlewareOptions = {
export type OverlayMiddlewareOptions = {
rootDirectory: string
stats(): webpack.Stats
}
@ -122,6 +123,41 @@ function getOverlayMiddleware(options: OverlayMiddlewareOptions) {
res.statusCode = 400
res.write('Bad Request')
return res.end()
} else if (pathname === '/__nextjs_launch-editor') {
const frame = (query as unknown) as StackFrame
const frameFile = frame.file?.toString() || null
if (frameFile == null) {
res.statusCode = 400
res.write('Bad Request')
return res.end()
}
const filePath = path.resolve(options.rootDirectory, frameFile)
const fileExists = await fs.access(filePath, FS.F_OK).then(
() => true,
() => false
)
if (!fileExists) {
res.statusCode = 404
res.write('Not Found')
return res.end()
}
const frameLine = parseInt(frame.lineNumber?.toString() ?? '', 10) || 1
const frameColumn = parseInt(frame.column?.toString() ?? '', 10) || 1
try {
await launchEditor(filePath, frameLine, frameColumn)
} catch (err) {
console.log('Failed to launch editor:', err)
res.statusCode = 500
res.write('Internal Server Error')
return res.end()
}
res.statusCode = 204
return res.end()
}
return next()
}

View file

@ -4443,6 +4443,14 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72"
integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"