@prismetic/next-preview-core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @prismetic/next-preview-core
2
+
3
+ Hybrid static/preview architecture for Next.js + Strapi projects.
4
+
5
+ Enables a production build that is a pure static export and a preview build hosted on S3 that fetches live Strapi content directly from the browser on page load — no Node.js server required.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @prismetic/next-preview-core
11
+ ```
12
+
13
+ Also requires `@tanstack/react-query` as a peer dependency:
14
+
15
+ ```bash
16
+ npm install @tanstack/react-query
17
+ ```
18
+
19
+ ## Exports
20
+
21
+ ### `PreviewProviders`
22
+
23
+ Wrap your preview layout in this provider to enable React Query caching. Layout data (Navbar, Footer) fetched once will not refetch on page navigation.
24
+
25
+ ```jsx
26
+ // src/app/[locale]/layout.jsx
27
+ import { PreviewProviders } from "@prismetic/next-preview-core";
28
+
29
+ const isPreview = process.env.NEXT_PUBLIC_APP_ENV === "preview";
30
+
31
+ return isPreview ? (
32
+ <PreviewProviders>
33
+ <YourPreviewLayoutFetcher locale={locale}>
34
+ {children}
35
+ </YourPreviewLayoutFetcher>
36
+ </PreviewProviders>
37
+ ) : (
38
+ // ... static layout
39
+ );
40
+ ```
41
+
42
+ ### `withLivePreview(WrappedComponent, fetcherFn, cacheKeyGenerator)`
43
+
44
+ A Higher-Order Component that handles `useQuery`, loading/error states, and injects fetched data into your UI component.
45
+
46
+ | Argument | Type | Description |
47
+ |---|---|---|
48
+ | `WrappedComponent` | `React.Component` | Your pure UI component |
49
+ | `fetcherFn` | `async (props) => data` | Async function that fetches the data |
50
+ | `cacheKeyGenerator` | `(props) => string[]` | Returns the React Query cache key array |
51
+
52
+ ```jsx
53
+ // src/components/preview/PreviewHome.jsx
54
+ "use client";
55
+
56
+ import { withLivePreview } from "@prismetic/next-preview-core";
57
+ import HomeUI from "@/app/[locale]/HomeUI";
58
+ import { fetchHomepageContent } from "@/api/queryModules";
59
+
60
+ export const PreviewHome = withLivePreview(
61
+ HomeUI,
62
+ ({ locale }) => fetchHomepageContent(locale),
63
+ ({ locale }) => ["homepage", locale]
64
+ );
65
+ ```
66
+
67
+ Then in your `page.jsx`:
68
+
69
+ ```jsx
70
+ // src/app/[locale]/page.jsx
71
+ import { PreviewHome } from "@/components/preview/PreviewHome";
72
+
73
+ export default async function LocaleHomePage({ params }) {
74
+ const { locale } = await params;
75
+ const isPreview = process.env.NEXT_PUBLIC_APP_ENV === "preview";
76
+
77
+ if (isPreview) return <PreviewHome locale={locale} />;
78
+
79
+ // Production: fetch data server-side
80
+ const data = await fetchHomepageContent(locale);
81
+ return <HomeUI data={data} />;
82
+ }
83
+ ```
84
+
85
+ ## Build Commands
86
+
87
+ | Command | Output |
88
+ |---|---|
89
+ | `npm run build` | Production static export (data baked in at build time) |
90
+ | `npm run build:preview` | Preview static export (client-side fetch on page load) |
91
+
92
+ Add to your `package.json`:
93
+
94
+ ```json
95
+ {
96
+ "scripts": {
97
+ "build": "next build",
98
+ "build:preview": "NEXT_PUBLIC_APP_ENV=preview next build"
99
+ }
100
+ }
101
+ ```
102
+
103
+ ## Local Development (npm link)
104
+
105
+ To test changes to this package in a project before publishing:
106
+
107
+ ```bash
108
+ # 1. In this package directory
109
+ npm link
110
+
111
+ # 2. In your project directory
112
+ npm link @prismetic/next-preview-core
113
+ ```
114
+
115
+ To unlink:
116
+ ```bash
117
+ npm unlink @prismetic/next-preview-core
118
+ ```
package/package.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@prismetic/next-preview-core",
3
+ "version": "1.0.0",
4
+ "description": "Hybrid static/preview architecture for Next.js + Strapi projects",
5
+ "main": "./src/index.ts",
6
+ "exports": {
7
+ ".": "./src/index.ts"
8
+ },
9
+ "keywords": [
10
+ "next.js",
11
+ "strapi",
12
+ "preview",
13
+ "static"
14
+ ],
15
+ "license": "MIT",
16
+ "peerDependencies": {
17
+ "react": ">=18",
18
+ "@tanstack/react-query": ">=5"
19
+ }
20
+ }
@@ -0,0 +1,35 @@
1
+ "use client";
2
+
3
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
4
+ import { useState } from "react";
5
+
6
+ /**
7
+ * React Query provider for Preview Mode.
8
+ * Part of @prismetic/next-preview-core.
9
+ *
10
+ * Wrap the preview build's component tree in this provider to enable
11
+ * client-side caching of Strapi data. Layout data (Navbar, Footer)
12
+ * fetched once will be served from the cache on subsequent page navigations.
13
+ *
14
+ * @param {number} [staleTime=300000] - How long (ms) cached data is considered fresh. Default: 5 minutes.
15
+ */
16
+ export function PreviewProviders({ children, staleTime = 5 * 60 * 1000 }) {
17
+ const [queryClient] = useState(
18
+ () =>
19
+ new QueryClient({
20
+ defaultOptions: {
21
+ queries: {
22
+ staleTime,
23
+ refetchOnWindowFocus: false,
24
+ retry: 1,
25
+ },
26
+ },
27
+ })
28
+ );
29
+
30
+ return (
31
+ <QueryClientProvider client={queryClient}>
32
+ {children}
33
+ </QueryClientProvider>
34
+ );
35
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ // @prismetic/next-preview-core
2
+ // Company-wide hybrid static/preview architecture for Next.js + Strapi projects
3
+
4
+ export { PreviewProviders } from "./PreviewProviders";
5
+ export { withLivePreview } from "./withLivePreview";
6
+
@@ -0,0 +1,49 @@
1
+ "use client";
2
+
3
+ import { useQuery } from "@tanstack/react-query";
4
+
5
+ /**
6
+ * A generic Higher-Order Component for Preview Mode data fetching.
7
+ * Part of @prismetic/next-preview-core.
8
+ *
9
+ * @param {React.Component} WrappedComponent - The pure UI component to render once data is fetched.
10
+ * @param {Function} fetcherFn - An async function that fetches data (receives component props as argument).
11
+ * @param {Function} cacheKeyGenerator - A function that returns a React Query queryKey array (receives component props).
12
+ *
13
+ * @example
14
+ * // In your project's preview wrapper:
15
+ * import { withLivePreview } from "@prismetic/next-preview-core";
16
+ * import HomeUI from "../HomeUI";
17
+ * import { fetchHomepageContent } from "@/api/queryModules";
18
+ *
19
+ * export const PreviewHome = withLivePreview(
20
+ * HomeUI,
21
+ * ({ locale }) => fetchHomepageContent(locale),
22
+ * ({ locale }) => ["homepage", locale]
23
+ * );
24
+ */
25
+ export function withLivePreview(WrappedComponent, fetcherFn, cacheKeyGenerator) {
26
+ return function PreviewComponent(props) {
27
+ const queryKey = cacheKeyGenerator(props);
28
+
29
+ const { data, isLoading } = useQuery({
30
+ queryKey,
31
+ queryFn: () => fetcherFn(props),
32
+ });
33
+
34
+ if (isLoading) {
35
+ return (
36
+ <div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center" }}>
37
+ Loading preview...
38
+ </div>
39
+ );
40
+ }
41
+
42
+ if (!data) {
43
+ return <div>Page not found</div>;
44
+ }
45
+
46
+ // Props spread first, then fetched data takes priority
47
+ return <WrappedComponent {...props} {...data} />;
48
+ };
49
+ }