Merge pull request #55 from bknd-io/feat/nextjs-plasmic-catchall

bknd/plasmic: added helper functions for integration
This commit is contained in:
dswbx
2025-01-25 09:03:30 +01:00
committed by GitHub
3 changed files with 151 additions and 8 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@bknd/plasmic",
"version": "0.5.0",
"version": "0.5.1",
"type": "module",
"sideEffects": false,
"scripts": {
@@ -30,9 +30,13 @@
"@plasmicapp/host": ">=1.0.0",
"@plasmicapp/loader-react": ">=1.0.0"
},
"optionalDependencies": {
"@plasmicapp/loader-nextjs": "^1.0.0"
},
"tsup": {
"entry": [
"src/index.ts"
"src/index.ts",
"src/nextjs/index.tsx"
],
"minify": true,
"clean": true,
@@ -42,7 +46,11 @@
"@plasmicapp/host",
"@plasmicapp/query",
"@plasmicapp/loader-react",
"swr"
"@plasmicapp/loader-nextjs",
"swr",
"next",
"next/error",
"next/router"
],
"format": [
"esm"
@@ -54,9 +62,19 @@
"sourceMap": true,
"outDir": "dist"
},
"types": "dist/index.d.ts",
"module": "dist/index.js",
"main": "dist/index.js",
"types": "./dist/index.d.ts",
"module": "./dist/index.js",
"main": "./dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./nextjs": {
"types": "./dist/nextjs/index.d.ts",
"import": "./dist/nextjs/index.js"
}
},
"files": [
"dist",
"README.md",

View File

@@ -6,7 +6,7 @@ import {
} from "@plasmicapp/host";
import { usePlasmicQueryData } from "@plasmicapp/loader-react";
import { useApi, useEntityQuery } from "bknd/client";
import type { RepoQuery } from "bknd/data";
import type { RepoQueryIn } from "bknd/data";
// biome-ignore lint/style/useImportType: <explanation>
import React from "react";
import { usePlasmicBkndContext } from "../../contexts/BkndContext";
@@ -171,7 +171,7 @@ type ModeProps = {
error?: React.ReactNode;
empty?: React.ReactNode;
entityId?: number;
query?: Partial<RepoQuery>;
query?: RepoQueryIn;
};
const ModeFetch = ({

View File

@@ -0,0 +1,125 @@
import {
type ComponentRenderData,
type NextJsPlasmicComponentLoader,
PlasmicComponent,
PlasmicRootProvider,
extractPlasmicQueryData
} from "@plasmicapp/loader-nextjs";
import type { GetStaticPaths, GetStaticProps, GetStaticPropsContext } from "next";
import NextjsError from "next/error";
import { useRouter } from "next/router";
import React from "react";
type TPlasmic = NextJsPlasmicComponentLoader;
export type TGetStaticPropsOptions = {
baseUrl?: string;
revalidate?: number | boolean;
};
export function plasmicNextjsStatic(PLASMIC: TPlasmic, opts?: TGetStaticPropsOptions) {
return {
getStaticPaths: getStaticPaths(PLASMIC),
getStaticProps: getStaticProps(PLASMIC, opts),
CatchallPage: CatchallPage(PLASMIC)
};
}
export function getStaticPaths(PLASMIC: TPlasmic): GetStaticPaths {
return async () => {
const pages = await PLASMIC.fetchPages();
return {
paths: pages.map((page) => ({
params: { catchall: page.path.substring(1).split("/") }
})),
fallback: "blocking"
};
};
}
export function getStaticProps(PLASMIC: TPlasmic, opts?: TGetStaticPropsOptions): GetStaticProps {
return async (context: GetStaticPropsContext) => {
const baseUrl = opts?.baseUrl ?? process.env.BASE_URL!;
let { catchall } = context.params ?? {};
if (catchall && Array.isArray(catchall) && catchall[0] === "index") {
console.log("setting catch all to undefined");
catchall = undefined;
}
const globalContextsProps = {
bkndContextProps: {
baseUrl
}
};
// Convert the catchall param into a path string
const plasmicPath =
typeof catchall === "string"
? catchall
: catchall !== null && Array.isArray(catchall)
? `/${catchall.join("/")}`
: "/";
const plasmicData = await PLASMIC.maybeFetchComponentData(plasmicPath);
if (!plasmicData) {
// This is some non-Plasmic catch-all page
return {
props: {}
};
}
// This is a path that Plasmic knows about.
const pageMeta = plasmicData.entryCompMetas[0];
// Cache the necessary data fetched for the page.
const queryCache = await extractPlasmicQueryData(
<PlasmicRootProvider
loader={PLASMIC}
prefetchedData={plasmicData}
pageRoute={pageMeta.path}
pageParams={pageMeta.params}
globalContextsProps={globalContextsProps}
>
<PlasmicComponent component={pageMeta.displayName} />
</PlasmicRootProvider>
);
const props = { plasmicData, queryCache, globalContextsProps };
// Pass the data in as props.
return {
props,
// Using incremental static regeneration, will invalidate this page
// after 300s (no deploy webhooks needed)
revalidate: opts?.revalidate ?? 300
};
};
}
export function CatchallPage(PLASMIC: TPlasmic) {
return (props: {
plasmicData?: ComponentRenderData;
queryCache?: Record<string, any>;
globalContextsProps?: any;
}) => {
const { plasmicData, queryCache, globalContextsProps } = props;
const router = useRouter();
if (!plasmicData || plasmicData.entryCompMetas.length === 0) {
return <NextjsError statusCode={404} />;
}
const pageMeta = plasmicData.entryCompMetas[0];
return (
<PlasmicRootProvider
loader={PLASMIC}
prefetchedData={plasmicData}
prefetchedQueryData={queryCache}
pageRoute={pageMeta.path}
pageParams={pageMeta.params}
pageQuery={router.query}
globalContextsProps={globalContextsProps}
>
<PlasmicComponent component={pageMeta.displayName} />
</PlasmicRootProvider>
);
};
}