Provide a good error message when loading react spectrum (#3406)

* Provide a good error message when loading react spectrum

* Adds a changeset
This commit is contained in:
Matthew Phillips 2022-05-19 13:12:04 -04:00 committed by GitHub
parent e9c137cf5f
commit 4007aebc6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 2362 additions and 6 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Provides a better error message when using @adobe/react-spectrum

View file

@ -41,9 +41,21 @@ export function fixViteErrorMessage(_err: unknown, server: ViteDevServer) {
return err;
}
const incompatiblePackages = {
'react-spectrum': `@adobe/react-spectrum is not compatible with Vite's server-side rendering mode at the moment. You can still use React Spectrum from the client. Create an island React component and use the client:only directive. From there you can use React Spectrum.`
};
const incompatPackageExp = new RegExp(`(${Object.keys(incompatiblePackages).join('|')})`);
function generateHint(err: ErrorWithMetadata): string | undefined {
if (/Unknown file extension \"\.(jsx|vue|svelte|astro)\" for /.test(err.message)) {
return 'You likely need to add this package to `vite.ssr.noExternal` in your astro config file.';
} else {
const res = incompatPackageExp.exec(err.stack);
if(res) {
const key = res[0] as keyof typeof incompatiblePackages;
return incompatiblePackages[key];
}
}
return undefined;
}

View file

@ -71,9 +71,9 @@ export default function template({
statusCode ? `<span class="statusCode">${statusCode}: </span> ` : ''
}<span class="statusMessage">${title}</span></h1>
</header>
<pre>${encode(error)}</pre>
<pre class="error-message">${encode(error)}</pre>
${url ? `<a target="_blank" href="${url}">${url}</a>` : ''}
<pre>${encode(stack)}</pre>
<pre class="error-stack">${encode(stack)}</pre>
</main>
</body>
</html>`;

View file

@ -37,6 +37,14 @@ function removeViteHttpMiddleware(server: vite.Connect.Server) {
}
}
function truncateString(str: string, n: number) {
if (str.length > n) {
return str.substring(0, n) + '&#8230;';
} else {
return str;
}
}
function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: string) {
res.writeHead(statusCode, {
'Content-Type': 'text/html; charset=utf-8',
@ -157,9 +165,9 @@ async function handle500Response(
statusCode: 500,
title: 'Internal Error',
tabTitle: '500: Error',
message: stripAnsi(err.message),
message: stripAnsi(err.hint ?? err.message),
url: err.url || undefined,
stack: stripAnsi(err.stack),
stack: truncateString(stripAnsi(err.stack), 500),
});
const transformedHtml = await viteServer.transformIndexHtml(pathname, html);
writeHtmlResponse(res, 500, transformedHtml);

View file

@ -0,0 +1,29 @@
import { isWindows, loadFixture } from './test-utils.js';
import { expect } from 'chai';
import * as cheerio from 'cheerio';
describe('Error packages: react-spectrum', () => {
if (isWindows) return;
/** @type {import('./test-utils').Fixture} */
let fixture;
/** @type {import('./test-utils').DevServer} */
let devServer;
before(async () => {
fixture = await loadFixture({
root: './fixtures/error-react-spectrum',
});
});
after(async () => {
devServer && devServer.stop();
});
it('properly detect syntax errors in template', async () => {
devServer = await fixture.startDevServer();
let html = await fixture.fetch('/').then(res => res.text());
let $ = cheerio.load(html);
const msg = $('.error-message').text();
expect(msg).to.match(/@adobe\/react-spectrum is not compatible/);
});
});

View file

@ -0,0 +1,7 @@
import { defineConfig } from 'astro/config';
import react from '@astrojs/react';
// https://astro.build/config
export default defineConfig({
integrations: [react()],
});

View file

@ -0,0 +1,15 @@
{
"name": "@test/error-react-spectrum",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*",
"@astrojs/react": "workspace:*",
"@adobe/react-spectrum": "^3.17.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}

View file

@ -0,0 +1,19 @@
---
// Just importing causes a failure
import '@adobe/react-spectrum';
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<style>
</style>
</head>
<body>
<main>
testing
</main>
</body>
</html>

File diff suppressed because it is too large Load diff