-
Notifications
You must be signed in to change notification settings - Fork 27.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make build error urls clickable (#46251)
Makes urls in build errors clickable by turning them into `<a>`. Reuses the `<HotlinkedText />` component in build errors that previously only was used in runtime errors. Also fixes an error that made the links break if they had `\n` before or after the url. Fixes NEXT-586 ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] [e2e](https://github.com/vercel/next.js/blob/canary/contributing/core/testing.md#writing-tests-for-nextjs) tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have a helpful link attached, see [`contributing.md`](https://github.com/vercel/next.js/blob/canary/contributing.md) ## Documentation / Examples - [ ] Make sure the linting passes by running `pnpm build && pnpm lint` - [ ] The "examples guidelines" are followed from [our contributing doc](https://github.com/vercel/next.js/blob/canary/contributing/examples/adding-examples.md)
- Loading branch information
1 parent
ab123c1
commit d38035c
Showing
7 changed files
with
162 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
17 changes: 17 additions & 0 deletions
17
...s/react-dev-overlay/internal/components/hot-linked-text/get-words-and-whitespaces.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { getWordsAndWhitespaces } from './get-words-and-whitespaces' | ||
|
||
describe('getWordsAndWhitespaces', () => { | ||
it('should return sequences of words and whitespaces', () => { | ||
const text = ' \n\nhello world https://nextjs.org/\nhttps://nextjs.org/' | ||
expect(getWordsAndWhitespaces(text)).toEqual([ | ||
' \n\n', | ||
'hello', | ||
' ', | ||
'world', | ||
' ', | ||
'https://nextjs.org/', | ||
'\n', | ||
'https://nextjs.org/', | ||
]) | ||
}) | ||
}) |
37 changes: 37 additions & 0 deletions
37
...onents/react-dev-overlay/internal/components/hot-linked-text/get-words-and-whitespaces.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
function isWhitespace(char: string) { | ||
return char === ' ' || char === '\n' | ||
} | ||
|
||
/** | ||
* Get sequences of words and whitespaces from a string. | ||
* | ||
* e.g. "Hello world \n\n" -> ["Hello", " ", "world", " \n\n"] | ||
*/ | ||
export function getWordsAndWhitespaces(text: string) { | ||
const wordsAndWhitespaces: string[] = [] | ||
|
||
let current = '' | ||
let currentIsWhitespace = false | ||
for (const char of text) { | ||
if (current.length === 0) { | ||
current += char | ||
currentIsWhitespace = isWhitespace(char) | ||
continue | ||
} | ||
|
||
const nextIsWhitespace = isWhitespace(char) | ||
if (currentIsWhitespace === nextIsWhitespace) { | ||
current += char | ||
} else { | ||
wordsAndWhitespaces.push(current) | ||
current = char | ||
currentIsWhitespace = nextIsWhitespace | ||
} | ||
} | ||
|
||
if (current.length > 0) { | ||
wordsAndWhitespaces.push(current) | ||
} | ||
|
||
return wordsAndWhitespaces | ||
} |
29 changes: 29 additions & 0 deletions
29
...ext/src/client/components/react-dev-overlay/internal/components/hot-linked-text/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import React from 'react' | ||
import { getWordsAndWhitespaces } from './get-words-and-whitespaces' | ||
|
||
const linkRegex = /https?:\/\/[^\s/$.?#].[^\s"]*/i | ||
|
||
export const HotlinkedText: React.FC<{ | ||
text: string | ||
}> = function HotlinkedText(props) { | ||
const { text } = props | ||
|
||
const wordsAndWhitespaces = getWordsAndWhitespaces(text) | ||
|
||
return ( | ||
<> | ||
{linkRegex.test(text) | ||
? wordsAndWhitespaces.map((word, index) => { | ||
if (linkRegex.test(word)) { | ||
return ( | ||
<React.Fragment key={`link-${index}`}> | ||
<a href={word}>{word}</a> | ||
</React.Fragment> | ||
) | ||
} | ||
return <React.Fragment key={`text-${index}`}>{word}</React.Fragment> | ||
}) | ||
: text} | ||
</> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { createNextDescribe, FileRef } from 'e2e-utils' | ||
import path from 'path' | ||
import { sandbox } from './helpers' | ||
|
||
createNextDescribe( | ||
'Error overlay - error message urls', | ||
{ | ||
files: new FileRef(path.join(__dirname, 'fixtures', 'default-template')), | ||
dependencies: { | ||
react: 'latest', | ||
'react-dom': 'latest', | ||
}, | ||
skipStart: true, | ||
}, | ||
({ next }) => { | ||
it('should be possible to click url in build error', async () => { | ||
const { session, browser, cleanup } = await sandbox(next) | ||
|
||
const content = await next.readFile('app/page.js') | ||
|
||
await session.patch( | ||
'app/page.js', | ||
content + '\nexport function getServerSideProps() {}' | ||
) | ||
|
||
expect(await session.hasRedbox(true)).toBe(true) | ||
|
||
const link = await browser.elementByCss('[data-nextjs-terminal] a') | ||
const text = await link.text() | ||
const href = await link.getAttribute('href') | ||
expect(text).toEqual( | ||
'https://beta.nextjs.org/docs/data-fetching/fundamentals' | ||
) | ||
expect(href).toEqual( | ||
'https://beta.nextjs.org/docs/data-fetching/fundamentals' | ||
) | ||
|
||
await cleanup() | ||
}) | ||
|
||
it('should be possible to click url in runtime error', async () => { | ||
const { session, browser, cleanup } = await sandbox( | ||
next, | ||
new Map([ | ||
[ | ||
'app/page.js', | ||
`'use client' | ||
export default function Page() { | ||
return typeof window === 'undefined' ? 'HELLO' : 'WORLD' | ||
} | ||
`, | ||
], | ||
]) | ||
) | ||
|
||
await session.waitForAndOpenRuntimeError() | ||
|
||
const link = await browser.elementByCss( | ||
'#nextjs__container_errors_desc a' | ||
) | ||
const text = await link.text() | ||
const href = await link.getAttribute('href') | ||
expect(text).toEqual( | ||
'https://nextjs.org/docs/messages/react-hydration-error' | ||
) | ||
expect(href).toEqual( | ||
'https://nextjs.org/docs/messages/react-hydration-error' | ||
) | ||
|
||
await cleanup() | ||
}) | ||
} | ||
) |