diff --git a/.changeset/early-bottles-cheat.md b/.changeset/early-bottles-cheat.md
new file mode 100644
index 000000000..eb44d7a81
--- /dev/null
+++ b/.changeset/early-bottles-cheat.md
@@ -0,0 +1,7 @@
+---
+'@myst-theme/site': minor
+'@myst-theme/article': patch
+'@myst-theme/book': patch
+---
+
+Prepare for Remix v2
diff --git a/packages/site/src/pages/Article.tsx b/packages/site/src/pages/Article.tsx
index 94be713c5..ebbf221c3 100644
--- a/packages/site/src/pages/Article.tsx
+++ b/packages/site/src/pages/Article.tsx
@@ -7,8 +7,6 @@ import {
FrontmatterParts,
BackmatterParts,
} from '../components/index.js';
-import { ErrorDocumentNotFound } from './ErrorDocumentNotFound.js';
-import { ErrorProjectNotFound } from './ErrorProjectNotFound.js';
import type { PageLoader } from '@myst-theme/common';
import { copyNode, type GenericParent } from 'myst-common';
import { SourceFileKind } from 'myst-spec-ext';
@@ -98,11 +96,3 @@ export const ArticlePage = React.memo(function ({
);
});
-
-export function ProjectPageCatchBoundary() {
- return ;
-}
-
-export function ArticlePageCatchBoundary() {
- return ;
-}
diff --git a/packages/site/src/pages/ErrorUnhandled.tsx b/packages/site/src/pages/ErrorUnhandled.tsx
new file mode 100644
index 000000000..90e3baa2b
--- /dev/null
+++ b/packages/site/src/pages/ErrorUnhandled.tsx
@@ -0,0 +1,14 @@
+export type ErrorResponse = {
+ status: number;
+ statusText: string;
+ data: any;
+};
+export function ErrorUnhandled({ error }: { error: ErrorResponse }) {
+ return (
+ <>
+
Unexpected Error Occurred
+ Status: {error.status}
+ {error.data.message}
+ >
+ );
+}
diff --git a/packages/site/src/pages/Root.tsx b/packages/site/src/pages/Root.tsx
index e9ceefc98..04cef5d9f 100644
--- a/packages/site/src/pages/Root.tsx
+++ b/packages/site/src/pages/Root.tsx
@@ -12,10 +12,13 @@ import {
useLoaderData,
Link,
NavLink,
+ useRouteError,
+ isRouteErrorResponse,
} from '@remix-run/react';
import { DEFAULT_NAV_HEIGHT, renderers as defaultRenderers } from '../components/index.js';
import { Analytics } from '../seo/index.js';
import { Error404 } from './Error404.js';
+import { ErrorUnhandled } from './ErrorUnhandled.js';
import classNames from 'classnames';
export function Document({
@@ -86,12 +89,13 @@ export function App() {
);
}
-export function AppCatchBoundary() {
+export function AppErrorBoundary() {
+ const error = useRouteError();
return (
-
+ {isRouteErrorResponse(error) ? : }
diff --git a/packages/site/src/pages/index.ts b/packages/site/src/pages/index.ts
index 50fed6991..8509c6c3a 100644
--- a/packages/site/src/pages/index.ts
+++ b/packages/site/src/pages/index.ts
@@ -1,5 +1,6 @@
export { ErrorProjectNotFound } from './ErrorProjectNotFound.js';
export { ErrorDocumentNotFound } from './ErrorDocumentNotFound.js';
export { Error404 } from './Error404.js';
-export { ArticlePage, ArticlePageCatchBoundary, ProjectPageCatchBoundary } from './Article.js';
-export { App, Document, AppCatchBoundary } from './Root.js';
+export { ErrorUnhandled } from './ErrorUnhandled.js';
+export { ArticlePage } from './Article.js';
+export { App, Document, AppErrorBoundary } from './Root.js';
diff --git a/packages/site/src/seo/meta.ts b/packages/site/src/seo/meta.ts
index 0b4625b6b..c4465f3bc 100644
--- a/packages/site/src/seo/meta.ts
+++ b/packages/site/src/seo/meta.ts
@@ -1,4 +1,4 @@
-import type { HtmlMetaDescriptor, V2_MetaDescriptor } from '@remix-run/react';
+import type { V2_MetaDescriptor } from '@remix-run/react';
type SocialSite = {
title: string;
@@ -17,15 +17,15 @@ type SocialArticle = {
keywords?: string[];
};
-function allDefined(meta: Record): HtmlMetaDescriptor {
- return Object.fromEntries(Object.entries(meta).filter(([, v]) => v)) as HtmlMetaDescriptor;
+function allDefined(meta: Record): V2_MetaDescriptor {
+ return Object.fromEntries(Object.entries(meta).filter(([, v]) => v)) as V2_MetaDescriptor;
}
export function getMetaTagsForSite_V1({
title,
description,
twitter,
-}: SocialSite): HtmlMetaDescriptor {
+}: SocialSite): V2_MetaDescriptor {
const meta = {
title,
description,
@@ -60,7 +60,7 @@ export function getMetaTagsForArticle_V1({
image,
twitter,
keywords,
-}: SocialArticle): HtmlMetaDescriptor {
+}: SocialArticle): V2_MetaDescriptor {
const meta = {
title,
description,
diff --git a/themes/article/app/root.tsx b/themes/article/app/root.tsx
index f307fbde7..a42782438 100644
--- a/themes/article/app/root.tsx
+++ b/themes/article/app/root.tsx
@@ -1,4 +1,4 @@
-import type { LinksFunction, MetaFunction, LoaderFunction, V2_MetaFunction } from '@remix-run/node';
+import type { LinksFunction, LoaderFunction, V2_MetaFunction } from '@remix-run/node';
import tailwind from '~/styles/app.css';
import thebeCoreCss from 'thebe-core/dist/lib/thebe-core.css';
import { getConfig } from '~/utils/loaders.server';
@@ -11,10 +11,10 @@ import {
ContentReload,
SkipToArticle,
} from '@myst-theme/site';
+export { AppErrorBoundary as ErrorBoundary } from '@myst-theme/site';
import { Outlet, useLoaderData } from '@remix-run/react';
-export { AppCatchBoundary as CatchBoundary } from '@myst-theme/site';
-export const meta: V2_MetaFunction = ({ data }) => {
+export const meta: V2_MetaFunction = ({ data }) => {
return getMetaTagsForSite({
title: data?.config?.title,
description: data?.config?.description,
diff --git a/themes/article/app/routes/$.tsx b/themes/article/app/routes/$.tsx
index e9a93451d..50b2bd20f 100644
--- a/themes/article/app/routes/$.tsx
+++ b/themes/article/app/routes/$.tsx
@@ -5,7 +5,12 @@ import {
type LoaderFunction,
type V2_MetaFunction,
} from '@remix-run/node';
-import { getMetaTagsForArticle, KatexCSS, ArticlePageCatchBoundary } from '@myst-theme/site';
+import {
+ getMetaTagsForArticle,
+ KatexCSS,
+ ErrorDocumentNotFound,
+ ErrorUnhandled,
+} from '@myst-theme/site';
import { getConfig, getPage } from '~/utils/loaders.server';
import { useLoaderData } from '@remix-run/react';
import type { SiteManifest } from 'myst-config';
@@ -14,10 +19,11 @@ import { ArticlePage } from '../components/ArticlePage';
import { ComputeOptionsProvider } from '@myst-theme/jupyter';
import { ProjectProvider, useBaseurl } from '@myst-theme/providers';
import { ThebeLoaderAndServer } from '@myst-theme/jupyter';
+import { useRouteError, isRouteErrorResponse } from '@remix-run/react';
type ManifestProject = Required['projects'][0];
-export const meta: V2_MetaFunction = ({ data, matches, location }) => {
+export const meta: V2_MetaFunction = ({ data, matches, location }) => {
if (!data) return [];
const config: SiteManifest = data.config;
@@ -77,11 +83,16 @@ export default function Page() {
);
}
-export function CatchBoundary() {
+export function ErrorBoundary() {
+ const error = useRouteError();
return (
-
+ {isRouteErrorResponse(error) ? (
+
+ ) : (
+
+ )}
);
diff --git a/themes/article/app/routes/_index.tsx b/themes/article/app/routes/_index.tsx
index a1f67919c..614435b20 100644
--- a/themes/article/app/routes/_index.tsx
+++ b/themes/article/app/routes/_index.tsx
@@ -1,4 +1,10 @@
-import { getMetaTagsForArticle, responseNoArticle, responseNoSite, ProjectPageCatchBoundary} from '@myst-theme/site';
+import {
+ getMetaTagsForArticle,
+ responseNoArticle,
+ responseNoSite,
+ ErrorDocumentNotFound,
+ ErrorUnhandled,
+} from '@myst-theme/site';
import Page from './$';
import { ArticlePageAndNavigation } from '../components/ArticlePageAndNavigation';
import { getConfig, getPage } from '../utils/loaders.server';
@@ -7,10 +13,11 @@ import { redirect } from '@remix-run/node';
import { SiteManifest } from 'myst-config';
import { getProject } from '@myst-theme/common';
export { links } from './$';
+import { useRouteError, isRouteErrorResponse } from '@remix-run/react';
type ManifestProject = Required['projects'][0];
-export const meta: V2_MetaFunction = ({ data, location }) => {
+export const meta: V2_MetaFunction = ({ data, location }) => {
if (!data) return [];
const config: SiteManifest = data.config;
@@ -39,11 +46,16 @@ export const loader: LoaderFunction = async ({ params, request }) => {
export default Page;
-export function CatchBoundary() {
+export function ErrorBoundary() {
+ const error = useRouteError();
return (
-
+ {isRouteErrorResponse(error) ? (
+
+ ) : (
+
+ )}
);
diff --git a/themes/article/remix.config.dev.js b/themes/article/remix.config.dev.js
index 7cfb8bf25..f2f6a921d 100644
--- a/themes/article/remix.config.dev.js
+++ b/themes/article/remix.config.dev.js
@@ -61,9 +61,11 @@ module.exports = {
],
watchPaths: ['../../packages/**/*'],
future: {
+ v2_dev: true,
v2_routeConvention: true,
v2_normalizeFormMethod: true,
v2_headers: true,
v2_meta: true,
+ v2_errorBoundary:true,
},
};
diff --git a/themes/article/remix.config.prod.js b/themes/article/remix.config.prod.js
index 4851a1a7d..98b056d33 100644
--- a/themes/article/remix.config.prod.js
+++ b/themes/article/remix.config.prod.js
@@ -12,5 +12,6 @@ module.exports = {
v2_normalizeFormMethod: true,
v2_headers: true,
v2_meta: true,
+ v2_errorBoundary:true,
},
};
diff --git a/themes/book/app/root.tsx b/themes/book/app/root.tsx
index 1c397c039..92aa7011a 100644
--- a/themes/book/app/root.tsx
+++ b/themes/book/app/root.tsx
@@ -11,10 +11,10 @@ import {
ContentReload,
SkipToArticle,
} from '@myst-theme/site';
+export { AppErrorBoundary as ErrorBoundary } from '@myst-theme/site';
import { Outlet, useLoaderData } from '@remix-run/react';
-export { AppCatchBoundary as CatchBoundary } from '@myst-theme/site';
-export const meta: V2_MetaFunction = ({ data }) => {
+export const meta: V2_MetaFunction = ({ data }) => {
return getMetaTagsForSite({
title: data?.config?.title,
description: data?.config?.description,
diff --git a/themes/book/app/routes/$.tsx b/themes/book/app/routes/$.tsx
index a12345dc2..09d586a29 100644
--- a/themes/book/app/routes/$.tsx
+++ b/themes/book/app/routes/$.tsx
@@ -12,7 +12,8 @@ import {
Navigation,
TopNav,
getMetaTagsForArticle,
- ArticlePageCatchBoundary,
+ ErrorDocumentNotFound,
+ ErrorUnhandled,
} from '@myst-theme/site';
import { getConfig, getPage } from '~/utils/loaders.server';
import { useLoaderData } from '@remix-run/react';
@@ -29,9 +30,10 @@ import { MadeWithMyst } from '@myst-theme/icons';
import { ComputeOptionsProvider, ThebeLoaderAndServer } from '@myst-theme/jupyter';
import { ArticlePage } from '../components/ArticlePage.js';
import type { TemplateOptions } from '../types.js';
+import { useRouteError, isRouteErrorResponse } from '@remix-run/react';
type ManifestProject = Required['projects'][0];
-export const meta: V2_MetaFunction = ({ data, matches, location }) => {
+export const meta: V2_MetaFunction = ({ data, matches, location }) => {
if (!data) return [];
const config: SiteManifest = data.config;
@@ -106,7 +108,6 @@ export function ArticlePageAndNavigation({
);
}
-
export default function Page() {
const { container } = useOutlineHeight();
const data = useLoaderData() as { page: PageLoader; project: ManifestProject };
@@ -136,11 +137,16 @@ export default function Page() {
);
}
-export function CatchBoundary() {
+export function ErrorBoundary() {
+ const error = useRouteError();
return (
-
+ {isRouteErrorResponse(error) ? (
+
+ ) : (
+
+ )}
);
diff --git a/themes/book/app/routes/_index.tsx b/themes/book/app/routes/_index.tsx
index fea6626a5..00c5428da 100644
--- a/themes/book/app/routes/_index.tsx
+++ b/themes/book/app/routes/_index.tsx
@@ -13,7 +13,7 @@ import { getProject } from '@myst-theme/common';
type ManifestProject = Required['projects'][0];
-export const meta: V2_MetaFunction = ({ data, location }) => {
+export const meta: V2_MetaFunction = ({ data, location }) => {
if (!data) return [];
const config: SiteManifest = data.config;
diff --git a/themes/book/remix.config.dev.js b/themes/book/remix.config.dev.js
index 7cfb8bf25..f2f6a921d 100644
--- a/themes/book/remix.config.dev.js
+++ b/themes/book/remix.config.dev.js
@@ -61,9 +61,11 @@ module.exports = {
],
watchPaths: ['../../packages/**/*'],
future: {
+ v2_dev: true,
v2_routeConvention: true,
v2_normalizeFormMethod: true,
v2_headers: true,
v2_meta: true,
+ v2_errorBoundary:true,
},
};
diff --git a/themes/book/remix.config.prod.js b/themes/book/remix.config.prod.js
index 4851a1a7d..9e2ad2b51 100644
--- a/themes/book/remix.config.prod.js
+++ b/themes/book/remix.config.prod.js
@@ -3,6 +3,7 @@ module.exports = {
appDirectory: 'app',
assetsBuildDirectory: 'public/build',
serverBuildPath: 'build/index.js',
+ serverModuleFormat: 'cjs',
serverMinify: true,
publicPath: '/myst_assets_folder/',
ignoredRouteFiles: ['**/.*'],
@@ -12,5 +13,6 @@ module.exports = {
v2_normalizeFormMethod: true,
v2_headers: true,
v2_meta: true,
+ v2_errorBoundary:true,
},
};