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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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>`;
|
||||
|
|
|
@ -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) {
|
||||
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);
|
||||
|
|
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
2265
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue