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, }, };