summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/calm-hotels-kiss.md5
-rw-r--r--packages/astro/src/runtime/server/render/component.ts62
2 files changed, 52 insertions, 15 deletions
diff --git a/.changeset/calm-hotels-kiss.md b/.changeset/calm-hotels-kiss.md
new file mode 100644
index 000000000..4b565fd9e
--- /dev/null
+++ b/.changeset/calm-hotels-kiss.md
@@ -0,0 +1,5 @@
+---
+"astro": patch
+---
+
+improves `client:only` error message
diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts
index b74fac9a6..70224ce9d 100644
--- a/packages/astro/src/runtime/server/render/component.ts
+++ b/packages/astro/src/runtime/server/render/component.ts
@@ -32,6 +32,7 @@ import { formatList, internalSpreadAttributes, renderElement, voidElementNames }
const needsHeadRenderingSymbol = Symbol.for('astro.needsHeadRendering');
const rendererAliases = new Map([['solid', 'solid-js']]);
+const clientOnlyValues = new Set(['solid-js', 'react', 'preact', 'vue', 'svelte', 'lit']);
function guessRenderers(componentUrl?: string): string[] {
const extname = componentUrl?.split('.').pop();
@@ -80,7 +81,7 @@ async function renderFrameworkComponent(
_props: Record<string | number, any>,
slots: any = {}
): Promise<RenderInstance> {
- if (!Component && !_props['client:only']) {
+ if (!Component && "client:only" in _props === false) {
throw new Error(
`Unable to render ${displayName} because it is ${Component}!\nDid you forget to import the component or is it possible there is a typo?`
);
@@ -164,13 +165,14 @@ async function renderFrameworkComponent(
} else {
// Attempt: use explicitly passed renderer name
if (metadata.hydrateArgs) {
- const passedName = metadata.hydrateArgs;
- const rendererName = rendererAliases.has(passedName)
- ? rendererAliases.get(passedName)
- : passedName;
- renderer = renderers.find(
- ({ name }) => name === `@astrojs/${rendererName}` || name === rendererName
- );
+ const rendererName = rendererAliases.has(metadata.hydrateArgs)
+ ? rendererAliases.get(metadata.hydrateArgs)
+ : metadata.hydrateArgs;
+ if (clientOnlyValues.has(rendererName)) {
+ renderer = renderers.find(
+ ({ name }) => name === `@astrojs/${rendererName}` || name === rendererName
+ );
+ }
}
// Attempt: user only has a single renderer, default to that
if (!renderer && validRenderers.length === 1) {
@@ -189,13 +191,34 @@ async function renderFrameworkComponent(
// If no one claimed the renderer
if (!renderer) {
if (metadata.hydrate === 'only') {
- throw new AstroError({
- ...AstroErrorData.NoClientOnlyHint,
- message: AstroErrorData.NoClientOnlyHint.message(metadata.displayName),
- hint: AstroErrorData.NoClientOnlyHint.hint(
- probableRendererNames.map((r) => r.replace('@astrojs/', '')).join('|')
- ),
- });
+ const rendererName = rendererAliases.has(metadata.hydrateArgs)
+ ? rendererAliases.get(metadata.hydrateArgs)
+ : metadata.hydrateArgs;
+ if (clientOnlyValues.has(rendererName)) {
+ // throw an error if provide correct client:only directive but not find the renderer
+ const plural = validRenderers.length > 1;
+ throw new AstroError({
+ ...AstroErrorData.NoMatchingRenderer,
+ message: AstroErrorData.NoMatchingRenderer.message(
+ metadata.displayName,
+ metadata?.componentUrl?.split('.').pop(),
+ plural,
+ validRenderers.length
+ ),
+ hint: AstroErrorData.NoMatchingRenderer.hint(
+ formatList(probableRendererNames.map((r) => '`' + r + '`'))
+ ),
+ });
+ } else {
+ // throw an error if an invalid hydration directive was provided
+ throw new AstroError({
+ ...AstroErrorData.NoClientOnlyHint,
+ message: AstroErrorData.NoClientOnlyHint.message(metadata.displayName),
+ hint: AstroErrorData.NoClientOnlyHint.hint(
+ probableRendererNames.map((r) => r.replace('@astrojs/', '')).join('|')
+ ),
+ });
+ }
} else if (typeof Component !== 'string') {
const matchingRenderers = validRenderers.filter((r) =>
probableRendererNames.includes(r.name)
@@ -241,6 +264,15 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
}
} else {
if (metadata.hydrate === 'only') {
+ const rendererName = rendererAliases.has(metadata.hydrateArgs)
+ ? rendererAliases.get(metadata.hydrateArgs)
+ : metadata.hydrateArgs;
+ if (!clientOnlyValues.has(rendererName)) {
+ // warning if provide incorrect client:only directive but find the renderer by guess
+ console.warn(
+ `The client:only directive for ${metadata.displayName} is not recognized. The renderer ${renderer.name} will be used. If you intended to use a different renderer, please provide a valid client:only directive.`
+ );
+ }
html = await renderSlotToString(result, slots?.fallback);
} else {
const componentRenderStartTime = performance.now();