Log pretty error when MDX integration is missing (#5761)
* feat: add MDX integration error handling * chore: changeset * docs: applied -> installed Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca> Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
This commit is contained in:
parent
0a6b87236a
commit
fa8c131f88
4 changed files with 57 additions and 7 deletions
5
.changeset/smart-clouds-applaud.md
Normal file
5
.changeset/smart-clouds-applaud.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add helpful error message when the MDX integration is missing.
|
|
@ -1,18 +1,29 @@
|
||||||
|
import type { SSRLoadedRenderer } from './../../../@types/astro.js';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import { getHighlighter } from 'shiki';
|
import { getHighlighter } from 'shiki';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import type { ErrorPayload } from 'vite';
|
import type { ErrorPayload } from 'vite';
|
||||||
import type { ModuleLoader } from '../../module-loader/index.js';
|
import type { ModuleLoader } from '../../module-loader/index.js';
|
||||||
import { AstroErrorData } from '../errors-data.js';
|
import { AstroErrorData } from '../errors-data.js';
|
||||||
import type { ErrorWithMetadata } from '../errors.js';
|
import { AstroError, ErrorWithMetadata } from '../errors.js';
|
||||||
import { createSafeError } from '../utils.js';
|
import { createSafeError } from '../utils.js';
|
||||||
import { renderErrorMarkdown } from './utils.js';
|
import { renderErrorMarkdown } from './utils.js';
|
||||||
|
|
||||||
export function enhanceViteSSRError(error: unknown, filePath?: URL, loader?: ModuleLoader): Error {
|
export function enhanceViteSSRError({
|
||||||
|
error,
|
||||||
|
filePath,
|
||||||
|
loader,
|
||||||
|
renderers,
|
||||||
|
}: {
|
||||||
|
error: unknown;
|
||||||
|
filePath?: URL;
|
||||||
|
loader?: ModuleLoader;
|
||||||
|
renderers?: SSRLoadedRenderer[];
|
||||||
|
}): Error {
|
||||||
// NOTE: We don't know where the error that's coming here comes from, so we need to be defensive regarding what we do
|
// NOTE: We don't know where the error that's coming here comes from, so we need to be defensive regarding what we do
|
||||||
// to it to make sure we keep as much information as possible. It's very possible that we receive an error that does not
|
// to it to make sure we keep as much information as possible. It's very possible that we receive an error that does not
|
||||||
// follow any kind of standard formats (ex: a number, a string etc)
|
// follow any kind of standard formats (ex: a number, a string etc)
|
||||||
const safeError = createSafeError(error) as ErrorWithMetadata;
|
let safeError = createSafeError(error) as ErrorWithMetadata;
|
||||||
|
|
||||||
// Vite will give you better stacktraces, using sourcemaps.
|
// Vite will give you better stacktraces, using sourcemaps.
|
||||||
if (loader) {
|
if (loader) {
|
||||||
|
@ -48,6 +59,23 @@ export function enhanceViteSSRError(error: unknown, filePath?: URL, loader?: Mod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fileId = safeError.id ?? safeError.loc?.file;
|
||||||
|
|
||||||
|
// Vite throws a syntax error trying to parse MDX without a plugin.
|
||||||
|
// Suggest installing the MDX integration if none is found.
|
||||||
|
if (
|
||||||
|
!renderers?.find((r) => r.name === '@astrojs/mdx') &&
|
||||||
|
safeError.message.match(/Syntax error/) &&
|
||||||
|
fileId?.match(/\.mdx$/)
|
||||||
|
) {
|
||||||
|
safeError = new AstroError({
|
||||||
|
...AstroErrorData.MdxIntegrationMissingError,
|
||||||
|
message: AstroErrorData.MdxIntegrationMissingError.message(fileId),
|
||||||
|
location: safeError.loc,
|
||||||
|
stack: safeError.stack,
|
||||||
|
}) as ErrorWithMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
// Since Astro.glob is a wrapper around Vite's import.meta.glob, errors don't show accurate information, let's fix that
|
// Since Astro.glob is a wrapper around Vite's import.meta.glob, errors don't show accurate information, let's fix that
|
||||||
if (/Invalid glob/.test(safeError.message)) {
|
if (/Invalid glob/.test(safeError.message)) {
|
||||||
const globPattern = safeError.message.match(/glob: "(.+)" \(/)?.[1];
|
const globPattern = safeError.message.match(/glob: "(.+)" \(/)?.[1];
|
||||||
|
|
|
@ -534,6 +534,23 @@ See https://docs.astro.build/en/guides/server-side-rendering/ for more informati
|
||||||
'A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.',
|
'A remark or rehype plugin attempted to inject invalid frontmatter. Ensure "astro.frontmatter" is set to a valid JSON object that is not `null` or `undefined`.',
|
||||||
hint: 'See the frontmatter injection docs https://docs.astro.build/en/guides/markdown-content/#modifying-frontmatter-programmatically for more information.',
|
hint: 'See the frontmatter injection docs https://docs.astro.build/en/guides/markdown-content/#modifying-frontmatter-programmatically for more information.',
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* @docs
|
||||||
|
* @see
|
||||||
|
* - [MDX installation and usage](https://docs.astro.build/en/guides/integrations-guide/mdx/)
|
||||||
|
* @description
|
||||||
|
* Unable to find the official `@astrojs/mdx` integration. This error is raised when using MDX files without an MDX integration installed.
|
||||||
|
*/
|
||||||
|
MdxIntegrationMissingError: {
|
||||||
|
title: 'MDX integration missing.',
|
||||||
|
code: 6004,
|
||||||
|
message: (id: string) => {
|
||||||
|
return `Unable to render ${JSON.stringify(
|
||||||
|
id
|
||||||
|
)}. Ensure that the \`@astrojs/mdx\` integration is installed.`;
|
||||||
|
},
|
||||||
|
hint: 'See the MDX integration docs for installation and usage instructions: https://docs.astro.build/en/guides/integrations-guide/mdx/',
|
||||||
|
},
|
||||||
// Config Errors - 7xxx
|
// Config Errors - 7xxx
|
||||||
UnknownConfigError: {
|
UnknownConfigError: {
|
||||||
title: 'Unknown configuration error.',
|
title: 'Unknown configuration error.',
|
||||||
|
|
|
@ -59,13 +59,13 @@ export async function preload({
|
||||||
// Load the module from the Vite SSR Runtime.
|
// Load the module from the Vite SSR Runtime.
|
||||||
const mod = (await env.loader.import(fileURLToPath(filePath))) as ComponentInstance;
|
const mod = (await env.loader.import(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
return [renderers, mod];
|
return [renderers, mod];
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
// If the error came from Markdown or CSS, we already handled it and there's no need to enhance it
|
// If the error came from Markdown or CSS, we already handled it and there's no need to enhance it
|
||||||
if (MarkdownError.is(err) || CSSError.is(err) || AggregateError.is(err)) {
|
if (MarkdownError.is(error) || CSSError.is(error) || AggregateError.is(error)) {
|
||||||
throw err;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw enhanceViteSSRError(err as Error, filePath, env.loader);
|
throw enhanceViteSSRError({ error, filePath, loader: env.loader, renderers });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue