diff --git a/packages/core/src/dev/components/error-page/DarkModeIcon.astro b/packages/core/src/dev/components/error-page/DarkModeIcon.astro
deleted file mode 100644
index 4edad01..0000000
--- a/packages/core/src/dev/components/error-page/DarkModeIcon.astro
+++ /dev/null
@@ -1,32 +0,0 @@
----
-interface Props {
- class?: string;
-}
-
-const { class: className } = Astro.props;
----
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/core/src/dev/components/error-page/ErrorDisplay.astro b/packages/core/src/dev/components/error-page/ErrorDisplay.astro
deleted file mode 100644
index 915ee72..0000000
--- a/packages/core/src/dev/components/error-page/ErrorDisplay.astro
+++ /dev/null
@@ -1,193 +0,0 @@
----
-import { Code } from "astro:components";
-import { readFile } from "node:fs/promises";
-import { transformerMetaHighlight } from "@shikijs/transformers";
-import { escapeHTML } from "astro/runtime/server/escape.js";
-import { createCssVariablesTheme } from "shiki";
-import type { ErrorWithMetadata } from "./types";
-
-interface Props {
- error: ErrorWithMetadata;
-}
-
-const { error } = Astro.props;
-
-const fullCode = error.loc?.file
- ? await readFile(error.loc.file, "utf-8")
- : undefined;
-
-const separator = error.loc?.file?.includes("/") ? "/" : "\\";
-const fileLocation = [
- error.loc?.file?.split(separator).slice(-2).join("/"),
- error.loc?.line,
- error.loc?.column,
-]
- .filter(Boolean)
- .join(":");
-
-const theme = createCssVariablesTheme({
- variablePrefix: "--astro-code-",
-});
-
-const errorHintText = escapeHTML(error.hint ?? "")
- .split(" ")
- .map((v) => {
- if (!v.startsWith("https://")) return v;
- if (v.endsWith("."))
- return `${v.slice(0, -1)}.`;
- return `${v}`;
- })
- .join(" ");
----
-
-
- {error.name}
-
- {error.message}
-
- {
- errorHintText && (
-
- )
- }
- {fileLocation && {fileLocation}
}
- {
- fullCode && (
-
- )
- }
-
-
-
-
-
-
-
diff --git a/packages/core/src/dev/components/error-page/ErrorPage.astro b/packages/core/src/dev/components/error-page/ErrorPage.astro
deleted file mode 100644
index 55cd305..0000000
--- a/packages/core/src/dev/components/error-page/ErrorPage.astro
+++ /dev/null
@@ -1,94 +0,0 @@
----
-import ErrorDisplay from "./ErrorDisplay.astro";
-import Header from "./Header.astro";
-import type { ErrorWithMetadata } from "./types";
-
-interface Props {
- error: ErrorWithMetadata;
-}
-
-const { error } = Astro.props;
----
-
-
-
-
- Error
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/core/src/dev/components/error-page/Header.astro b/packages/core/src/dev/components/error-page/Header.astro
deleted file mode 100644
index 4def227..0000000
--- a/packages/core/src/dev/components/error-page/Header.astro
+++ /dev/null
@@ -1,87 +0,0 @@
----
-import DarkModeIcon from "./DarkModeIcon.astro";
-import LightModeIcon from "./LightModeIcon.astro";
-import MightyLogo from "./MightyLogo.astro";
----
-
-
-
-
-
-
diff --git a/packages/core/src/dev/components/error-page/LightModeIcon.astro b/packages/core/src/dev/components/error-page/LightModeIcon.astro
deleted file mode 100644
index faec933..0000000
--- a/packages/core/src/dev/components/error-page/LightModeIcon.astro
+++ /dev/null
@@ -1,36 +0,0 @@
----
-interface Props {
- class?: string;
-}
-
-const { class: className } = Astro.props;
----
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/core/src/dev/components/error-page/MightyLogo.astro b/packages/core/src/dev/components/error-page/MightyLogo.astro
deleted file mode 100644
index 102ea80..0000000
--- a/packages/core/src/dev/components/error-page/MightyLogo.astro
+++ /dev/null
@@ -1,71 +0,0 @@
----
-interface Props {
- class?: string;
-}
-
-const { class: className } = Astro.props;
----
-
-
diff --git a/packages/core/src/dev/components/error-page/types.ts b/packages/core/src/dev/components/error-page/types.ts
deleted file mode 100644
index 39617c9..0000000
--- a/packages/core/src/dev/components/error-page/types.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-type ErrorTypes =
- | "AstroError"
- | "AstroUserError"
- | "CompilerError"
- | "CSSError"
- | "MarkdownError"
- | "InternalError"
- | "AggregateError";
-
-export interface ErrorWithMetadata {
- name: string;
- type?: ErrorTypes;
- message: string;
- stack: string;
- hint?: string;
- loc?: {
- file?: string;
- line?: number;
- column?: number;
- };
-}
diff --git a/packages/core/src/dev/index.ts b/packages/core/src/dev/index.ts
index 81f657d..9699ff8 100644
--- a/packages/core/src/dev/index.ts
+++ b/packages/core/src/dev/index.ts
@@ -1,11 +1,11 @@
-import type { MightyDevMiddleware, MightyDevOptions } from "@/types";
+import type { MightyDevMiddleware, MightyServerOptions } from "@/types";
import { setupDev } from "./setup";
/**
* Starts the Mighty development server.
*/
export async function dev(
- options: MightyDevOptions,
+ options: MightyServerOptions,
): Promise {
return setupDev(options);
}
diff --git a/packages/core/src/dev/setup.ts b/packages/core/src/dev/setup.ts
index 5bb1e05..b0102b5 100644
--- a/packages/core/src/dev/setup.ts
+++ b/packages/core/src/dev/setup.ts
@@ -12,8 +12,8 @@ import type { ViteDevServer } from "vite";
import { getStylesForURL } from "@/dev/css";
import type {
MightyDevMiddleware,
- MightyDevOptions,
MightyRenderDevRequest,
+ MightyServerOptions,
} from "@/types";
import { dotStringToPath } from "@/utils/dotStringToPath";
import { injectTagsIntoHead } from "@/utils/injectTagsIntoHead";
@@ -31,7 +31,7 @@ const require = createRequire(import.meta.url);
const devDir = path.join(path.dirname(require.resolve("@gomighty/core/dev")));
export async function setupDev(
- options: MightyDevOptions,
+ options: MightyServerOptions,
): Promise {
let finalConfig: AstroConfig;
let viteServer: ViteDevServer;
@@ -42,9 +42,6 @@ export async function setupDev(
server: {
middlewareMode: true,
cors: false,
- hmr: {
- overlay: false,
- },
},
plugins: [
{
@@ -141,67 +138,12 @@ export async function setupDev(
]
: () => [];
- const renderComponentByPath = async (
- data: Omit & {
- componentPath: `${string}.astro`;
- },
- ) => {
- const { componentPath, props, context, partial = true, address } = data;
-
- const [rawRenderedComponent, styleTags] = await Promise.all([
- renderComponent({
- componentPath,
- props,
- context,
- partial,
- }),
- getStylesForURL(componentPath, viteServer).then((styles): Element[] =>
- styles.styles.map((style) => ({
- type: "element",
- tagName: "style",
- properties: {
- type: "text/css",
- "data-vite-dev-id": style.id,
- },
- children: [{ type: "text", value: style.content }],
- })),
- ),
- ]);
-
- // Rewrite image URLs to include the dev address
- const renderedComponent = rawRenderedComponent.replace(
- /(["'(])\/@fs\//g,
- `$1${MIGHTY_DEV_PLACEHOLDER_ADDRESS}/@fs/`,
- );
-
- const viteClientScript: Element = {
- type: "element",
- tagName: "script",
- properties: {
- type: "module",
- src: `${MIGHTY_DEV_PLACEHOLDER_ADDRESS}/@vite/client`,
- },
- children: [],
- };
-
- return injectTagsIntoHead(
- renderedComponent,
- [
- ...styleTags,
- viteClientScript,
- ...getPageScripts(),
- ...headInlineScriptTags,
- ],
- partial,
- ).replaceAll(MIGHTY_DEV_PLACEHOLDER_ADDRESS, address);
- };
-
return {
viteMiddleware: viteServer.middlewares,
stop: () => viteServer.close(),
render: async (request: MightyRenderDevRequest) => {
try {
- const { component, props, context, partial, address } = request;
+ const { component, props, context, partial = true, address } = request;
const componentPath: `${string}.astro` = `${path.join(
finalConfig.srcDir.pathname,
@@ -216,39 +158,75 @@ export async function setupDev(
return { status: 404, content: `Component ${component} not found` };
}
- return {
- status: 200,
- content: await renderComponentByPath({
+ const [rawRenderedComponent, styleTags] = await Promise.all([
+ renderComponent({
componentPath,
props,
context,
partial,
- address,
}),
+ getStylesForURL(componentPath, viteServer).then((styles): Element[] =>
+ styles.styles.map((style) => ({
+ type: "element",
+ tagName: "style",
+ properties: {
+ type: "text/css",
+ "data-vite-dev-id": style.id,
+ },
+ children: [{ type: "text", value: style.content }],
+ })),
+ ),
+ ]);
+
+ // Rewrite image URLs to include the dev address
+ const renderedComponent = rawRenderedComponent.replace(
+ /(["'(])\/@fs\//g,
+ `$1${MIGHTY_DEV_PLACEHOLDER_ADDRESS}/@fs/`,
+ );
+
+ const viteClientScript: Element = {
+ type: "element",
+ tagName: "script",
+ properties: {
+ type: "module",
+ src: `${MIGHTY_DEV_PLACEHOLDER_ADDRESS}/@vite/client`,
+ },
+ children: [],
};
+
+ const content = injectTagsIntoHead(
+ renderedComponent,
+ [
+ ...styleTags,
+ viteClientScript,
+ ...getPageScripts(),
+ ...headInlineScriptTags,
+ ],
+ partial,
+ ).replaceAll(MIGHTY_DEV_PLACEHOLDER_ADDRESS, address);
+
+ return { status: 200, content };
} catch (error) {
viteServer.ssrFixStacktrace(error as Error);
- if (!(options.showErrorPage ?? true)) {
+ const hmr = finalConfig.vite?.server?.hmr;
+ const overlayEnabled =
+ typeof hmr === "object" ? hmr.overlay !== false : hmr !== false;
+
+ if (!overlayEnabled) {
throw error;
}
+ setTimeout(() => {
+ viteServer.environments.client.hot.send({
+ type: "error",
+ err: error as Error & { stack: string },
+ });
+ }, 200);
+
return {
status: 500,
- content: await renderComponentByPath({
- componentPath: path.join(
- devDir,
- "components",
- "error-page",
- "ErrorPage.astro",
- ) as `${string}.astro`,
- props: {
- error: error as Error,
- },
- context: {},
- partial: false,
- address: request.address,
- }),
+ content: `${(error as Error).name}`,
};
}
},
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index afa69a2..ba9170f 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -12,14 +12,6 @@ export type MightyServerOptions = {
config?: AstroInlineConfig;
};
-export type MightyDevOptions = MightyServerOptions & {
- /**
- * Whether to show the Mighty error page when an error occurs.
- * @default true
- */
- showErrorPage?: boolean;
-};
-
export type MightyStartOptions = MightyServerOptions;
export type MightyRenderRequest = {
diff --git a/packages/core/tests/dev/error.test.ts b/packages/core/tests/dev/error.test.ts
index 008ed51..c163f1e 100644
--- a/packages/core/tests/dev/error.test.ts
+++ b/packages/core/tests/dev/error.test.ts
@@ -14,7 +14,7 @@ describe("dev error fixture", () => {
await fixture.clean();
});
- it("can render an error page", async () => {
+ it("renders the Astro error overlay", async () => {
const { render } = await fixture.startDevServer({
config: { logLevel: "silent" },
});
@@ -26,37 +26,17 @@ describe("dev error fixture", () => {
partial: false,
});
expect(response.status).toBe(500);
- expect(response.content).toContain("Error");
expect(response.content).toContain(
'',
);
- expect(response.content).toContain("pages/error.astro:2:1");
});
- it("renders an error page when showErrorPage is true", async () => {
+ it("throws an error when hmr.overlay is false", async () => {
const { render } = await fixture.startDevServer({
- showErrorPage: true,
- config: { logLevel: "silent" },
- });
-
- const response = await render({
- component: "error",
- props: {},
- context: {},
- partial: false,
- });
- expect(response.status).toBe(500);
- expect(response.content).toContain("Error");
- expect(response.content).toContain(
- '',
- );
- expect(response.content).toContain("pages/error.astro:2:1");
- });
-
- it("throws an error when showErrorPage is false", async () => {
- const { render } = await fixture.startDevServer({
- showErrorPage: false,
- config: { logLevel: "silent" },
+ config: {
+ logLevel: "silent",
+ vite: { server: { hmr: { overlay: false } } },
+ },
});
await expect(
diff --git a/packages/core/tests/fixture.ts b/packages/core/tests/fixture.ts
index 30beba2..482cd14 100644
--- a/packages/core/tests/fixture.ts
+++ b/packages/core/tests/fixture.ts
@@ -6,11 +6,7 @@ import { toFetchResponse, toReqRes } from "fetch-to-node";
import { build } from "@/build";
import { setupDev } from "@/dev/setup";
import { setupStart } from "@/start/setup";
-import type {
- MightyDevOptions,
- MightyRenderRequest,
- MightyServerOptions,
-} from "@/types";
+import type { MightyRenderRequest, MightyServerOptions } from "@/types";
import { dotStringToPath } from "@/utils/dotStringToPath";
export type DevRenderFunction = (
@@ -27,7 +23,7 @@ export type GetFromViteMiddlewareFunction = (
export function getFixture(fixtureName: string): {
fixtureRoot: string;
outDir: string;
- startDevServer: (params?: MightyDevOptions) => Promise<{
+ startDevServer: (params?: MightyServerOptions) => Promise<{
render: DevRenderFunction;
getFromViteMiddleware: GetFromViteMiddlewareFunction;
stop: () => Promise;
diff --git a/packages/hono/src/dev.ts b/packages/hono/src/dev.ts
index 1f1ebc3..ea285d2 100644
--- a/packages/hono/src/dev.ts
+++ b/packages/hono/src/dev.ts
@@ -1,4 +1,4 @@
-import { dev, type MightyDevOptions } from "@gomighty/core";
+import { dev, type MightyServerOptions } from "@gomighty/core";
import { mergeConfig } from "astro/config";
import { createMiddleware } from "hono/factory";
import type { UnofficialStatusCode } from "hono/utils/http-status";
@@ -8,9 +8,9 @@ import { runConnectMiddleware } from "./utils/runConnectMiddleware.ts";
const MIGHTY_DEV_ROOT = "/__MIGHTY_DEV_ADDRESS__";
export function devMiddleware(
- options?: MightyDevOptions,
+ options?: MightyServerOptions,
): StartMightyServerMiddlewareHandler {
- const mightyConfig: MightyDevOptions = {
+ const mightyConfig: MightyServerOptions = {
...options,
config: mergeConfig(
{ root: "./astro", vite: { base: MIGHTY_DEV_ROOT } },
@@ -23,7 +23,11 @@ export function devMiddleware(
return createMiddleware(async (c, next) => {
const { render, viteMiddleware } = await setupDevPromise;
- if (c.req.method === "GET" && c.req.path.includes(MIGHTY_DEV_ROOT)) {
+ if (
+ c.req.method === "GET" &&
+ (c.req.path.includes(MIGHTY_DEV_ROOT) ||
+ c.req.path === "/__open-in-editor")
+ ) {
return runConnectMiddleware(viteMiddleware, c);
}