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:
parent
e9c137cf5f
commit
4007aebc6a
9 changed files with 2362 additions and 6 deletions
5
.changeset/poor-ways-relax.md
Normal file
5
.changeset/poor-ways-relax.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Provides a better error message when using @adobe/react-spectrum
|
|
@ -41,9 +41,21 @@ export function fixViteErrorMessage(_err: unknown, server: ViteDevServer) {
|
||||||
return err;
|
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 {
|
function generateHint(err: ErrorWithMetadata): string | undefined {
|
||||||
if (/Unknown file extension \"\.(jsx|vue|svelte|astro)\" for /.test(err.message)) {
|
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.';
|
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;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,9 +71,9 @@ export default function template({
|
||||||
statusCode ? `<span class="statusCode">${statusCode}: </span> ` : ''
|
statusCode ? `<span class="statusCode">${statusCode}: </span> ` : ''
|
||||||
}<span class="statusMessage">${title}</span></h1>
|
}<span class="statusMessage">${title}</span></h1>
|
||||||
</header>
|
</header>
|
||||||
<pre>${encode(error)}</pre>
|
<pre class="error-message">${encode(error)}</pre>
|
||||||
${url ? `<a target="_blank" href="${url}">${url}</a>` : ''}
|
${url ? `<a target="_blank" href="${url}">${url}</a>` : ''}
|
||||||
<pre>${encode(stack)}</pre>
|
<pre class="error-stack">${encode(stack)}</pre>
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>`;
|
</html>`;
|
||||||
|
|
|
@ -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) + '…';
|
||||||
|
} else {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: string) {
|
function writeHtmlResponse(res: http.ServerResponse, statusCode: number, html: string) {
|
||||||
res.writeHead(statusCode, {
|
res.writeHead(statusCode, {
|
||||||
'Content-Type': 'text/html; charset=utf-8',
|
'Content-Type': 'text/html; charset=utf-8',
|
||||||
|
@ -157,9 +165,9 @@ async function handle500Response(
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
title: 'Internal Error',
|
title: 'Internal Error',
|
||||||
tabTitle: '500: Error',
|
tabTitle: '500: Error',
|
||||||
message: stripAnsi(err.message),
|
message: stripAnsi(err.hint ?? err.message),
|
||||||
url: err.url || undefined,
|
url: err.url || undefined,
|
||||||
stack: stripAnsi(err.stack),
|
stack: truncateString(stripAnsi(err.stack), 500),
|
||||||
});
|
});
|
||||||
const transformedHtml = await viteServer.transformIndexHtml(pathname, html);
|
const transformedHtml = await viteServer.transformIndexHtml(pathname, html);
|
||||||
writeHtmlResponse(res, 500, transformedHtml);
|
writeHtmlResponse(res, 500, transformedHtml);
|
||||||
|
|
29
packages/astro/test/error-react-spectrum.test.js
Normal file
29
packages/astro/test/error-react-spectrum.test.js
Normal 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/);
|
||||||
|
});
|
||||||
|
});
|
7
packages/astro/test/fixtures/error-react-spectrum/astro.config.mjs
vendored
Normal file
7
packages/astro/test/fixtures/error-react-spectrum/astro.config.mjs
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import react from '@astrojs/react';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({
|
||||||
|
integrations: [react()],
|
||||||
|
});
|
15
packages/astro/test/fixtures/error-react-spectrum/package.json
vendored
Normal file
15
packages/astro/test/fixtures/error-react-spectrum/package.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
19
packages/astro/test/fixtures/error-react-spectrum/src/pages/index.astro
vendored
Normal file
19
packages/astro/test/fixtures/error-react-spectrum/src/pages/index.astro
vendored
Normal 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>
|
2265
pnpm-lock.yaml
generated
2265
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue