@nextsparkjs/core 0.1.0-beta.132 → 0.1.0-beta.133
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/dist/components/public/pageBuilder/PageRenderer.d.ts +6 -1
- package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
- package/dist/components/public/pageBuilder/PageRenderer.js +3 -11
- package/dist/lib/blocks/loader.d.ts +9 -0
- package/dist/lib/blocks/loader.d.ts.map +1 -1
- package/dist/lib/blocks/loader.js +9 -1
- package/dist/styles/classes.json +1 -1
- package/package.json +2 -2
- package/scripts/build/registry/generators/block-registry.mjs +29 -0
- package/scripts/build/registry/generators/plugin-registry.mjs +1 -1
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.ts +2 -0
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* PageRenderer Component
|
|
3
3
|
*
|
|
4
4
|
* Renders pages from the Page Builder by iterating over blocks
|
|
5
|
-
* and
|
|
5
|
+
* and directly loading block components from the SSR registry.
|
|
6
|
+
*
|
|
7
|
+
* Uses direct imports (BLOCK_COMPONENTS_SSR) instead of React.lazy
|
|
8
|
+
* so that all HTML is visible in the initial server response without JS.
|
|
9
|
+
* React.lazy puts content inside hidden <template> tags that require
|
|
10
|
+
* client-side JS to reveal — breaking no-JS rendering and hurting SEO.
|
|
6
11
|
*
|
|
7
12
|
* @module core/components/public/pageBuilder
|
|
8
13
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PageRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/public/pageBuilder/PageRenderer.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"PageRenderer.d.ts","sourceRoot":"","sources":["../../../../src/components/public/pageBuilder/PageRenderer.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAkC1D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,KAAK,EAAE,MAAM,CAAA;QACb,IAAI,EAAE,MAAM,CAAA;QACZ,MAAM,EAAE,aAAa,EAAE,CAAA;QACvB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,wBAAgB,YAAY,CAAC,EAAE,IAAI,EAAE,EAAE,iBAAiB,2CA+BvD"}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
3
|
-
import { getBlockComponent, normalizeBlockProps } from "../../../lib/blocks/loader.js";
|
|
4
|
-
function BlockSkeleton() {
|
|
5
|
-
return /* @__PURE__ */ jsx("div", { className: "w-full py-12 px-4 animate-pulse", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
|
|
6
|
-
/* @__PURE__ */ jsx("div", { className: "h-8 bg-muted rounded w-3/4 mb-4" }),
|
|
7
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-full mb-2" }),
|
|
8
|
-
/* @__PURE__ */ jsx("div", { className: "h-4 bg-muted rounded w-5/6" })
|
|
9
|
-
] }) });
|
|
10
|
-
}
|
|
2
|
+
import { getBlockComponentSSR, normalizeBlockProps } from "../../../lib/blocks/loader.js";
|
|
11
3
|
function BlockError({ blockSlug }) {
|
|
12
4
|
return /* @__PURE__ */ jsx("div", { className: "w-full py-12 px-4 bg-destructive/10 border border-destructive/20 rounded", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto text-center", children: [
|
|
13
5
|
/* @__PURE__ */ jsxs("p", { className: "text-destructive", children: [
|
|
@@ -18,13 +10,13 @@ function BlockError({ blockSlug }) {
|
|
|
18
10
|
] }) });
|
|
19
11
|
}
|
|
20
12
|
function BlockRenderer({ block }) {
|
|
21
|
-
const BlockComponent =
|
|
13
|
+
const BlockComponent = getBlockComponentSSR(block.blockSlug);
|
|
22
14
|
if (!BlockComponent) {
|
|
23
15
|
console.warn(`Block component not found for slug: ${block.blockSlug}`);
|
|
24
16
|
return /* @__PURE__ */ jsx(BlockError, { blockSlug: block.blockSlug });
|
|
25
17
|
}
|
|
26
18
|
const normalizedProps = normalizeBlockProps(block.props);
|
|
27
|
-
return /* @__PURE__ */ jsx(
|
|
19
|
+
return /* @__PURE__ */ jsx(BlockComponent, { ...normalizedProps });
|
|
28
20
|
}
|
|
29
21
|
function PageRenderer({ page }) {
|
|
30
22
|
const blocks = Array.isArray(page.blocks) ? page.blocks : [];
|
|
@@ -22,6 +22,15 @@ export declare function getBlockComponents(): Record<string, BlockComponent>;
|
|
|
22
22
|
* @returns The block component or undefined if not found
|
|
23
23
|
*/
|
|
24
24
|
export declare function getBlockComponent(slug: string): BlockComponent | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Get all SSR block components (direct imports, no React.lazy)
|
|
27
|
+
* Use for public page rendering where no-JS SSR is required
|
|
28
|
+
*/
|
|
29
|
+
export declare function getBlockComponentsSSR(): Record<string, BlockComponent>;
|
|
30
|
+
/**
|
|
31
|
+
* Get a specific SSR block component by slug (direct import, no React.lazy)
|
|
32
|
+
*/
|
|
33
|
+
export declare function getBlockComponentSSR(slug: string): BlockComponent | undefined;
|
|
25
34
|
/**
|
|
26
35
|
* Check if a block exists in the registry
|
|
27
36
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/lib/blocks/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAIrC,KAAK,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgD3F"}
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/lib/blocks/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAIrC,KAAK,cAAc,GAAG,aAAa,CAAC,GAAG,CAAC,CAAA;AAExC;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEnE;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE1E;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAEtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAE7E;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgD3F"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { BLOCK_COMPONENTS } from "@nextsparkjs/registries/block-registry";
|
|
1
|
+
import { BLOCK_COMPONENTS, BLOCK_COMPONENTS_SSR } from "@nextsparkjs/registries/block-registry";
|
|
2
2
|
function getBlockComponents() {
|
|
3
3
|
return BLOCK_COMPONENTS;
|
|
4
4
|
}
|
|
5
5
|
function getBlockComponent(slug) {
|
|
6
6
|
return BLOCK_COMPONENTS[slug];
|
|
7
7
|
}
|
|
8
|
+
function getBlockComponentsSSR() {
|
|
9
|
+
return BLOCK_COMPONENTS_SSR;
|
|
10
|
+
}
|
|
11
|
+
function getBlockComponentSSR(slug) {
|
|
12
|
+
return BLOCK_COMPONENTS_SSR[slug];
|
|
13
|
+
}
|
|
8
14
|
function hasBlock(slug) {
|
|
9
15
|
return slug in BLOCK_COMPONENTS;
|
|
10
16
|
}
|
|
@@ -48,7 +54,9 @@ function normalizeBlockProps(props) {
|
|
|
48
54
|
}
|
|
49
55
|
export {
|
|
50
56
|
getBlockComponent,
|
|
57
|
+
getBlockComponentSSR,
|
|
51
58
|
getBlockComponents,
|
|
59
|
+
getBlockComponentsSSR,
|
|
52
60
|
hasBlock,
|
|
53
61
|
normalizeBlockProps
|
|
54
62
|
};
|
package/dist/styles/classes.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.133",
|
|
4
4
|
"description": "NextSpark - The complete SaaS framework for Next.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NextSpark <hello@nextspark.dev>",
|
|
@@ -462,7 +462,7 @@
|
|
|
462
462
|
"tailwind-merge": "^3.3.1",
|
|
463
463
|
"uuid": "^13.0.0",
|
|
464
464
|
"zod": "^4.1.5",
|
|
465
|
-
"@nextsparkjs/testing": "0.1.0-beta.
|
|
465
|
+
"@nextsparkjs/testing": "0.1.0-beta.133"
|
|
466
466
|
},
|
|
467
467
|
"scripts": {
|
|
468
468
|
"postinstall": "node scripts/postinstall.mjs || true",
|
|
@@ -47,6 +47,13 @@ export const BLOCK_CATEGORIES: string[] = []
|
|
|
47
47
|
|
|
48
48
|
export const BLOCK_COMPONENTS: Record<string, React.LazyExoticComponent<React.ComponentType<unknown>>> = {}
|
|
49
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Direct-imported block components for SSR rendering
|
|
52
|
+
* No React.lazy, no Suspense — HTML is fully visible without JS
|
|
53
|
+
*/
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {}
|
|
56
|
+
|
|
50
57
|
export const BLOCK_METADATA = {
|
|
51
58
|
totalBlocks: 0,
|
|
52
59
|
categories: [],
|
|
@@ -59,6 +66,8 @@ export const BLOCK_METADATA = {
|
|
|
59
66
|
|
|
60
67
|
// Import field definitions and examples (if they exist)
|
|
61
68
|
const imports = []
|
|
69
|
+
// Direct component imports for SSR (no React.lazy)
|
|
70
|
+
const ssrImports = []
|
|
62
71
|
|
|
63
72
|
blocks.forEach(block => {
|
|
64
73
|
const slugVar = block.slug.replace(/-/g, '_')
|
|
@@ -66,6 +75,9 @@ export const BLOCK_METADATA = {
|
|
|
66
75
|
// Always import field definitions
|
|
67
76
|
imports.push(`import { fieldDefinitions as ${slugVar}_fields } from '${block.paths.fields}'`)
|
|
68
77
|
|
|
78
|
+
// Direct component import for SSR rendering
|
|
79
|
+
ssrImports.push(`import { default as ${slugVar}_component } from '${block.paths.component}'`)
|
|
80
|
+
|
|
69
81
|
// Conditionally import examples if they exist
|
|
70
82
|
if (block.hasExamples) {
|
|
71
83
|
imports.push(`import { examples as ${slugVar}_examples } from '${block.paths.examples}'`)
|
|
@@ -73,6 +85,7 @@ export const BLOCK_METADATA = {
|
|
|
73
85
|
})
|
|
74
86
|
|
|
75
87
|
const fieldImports = imports.join('\n')
|
|
88
|
+
const ssrComponentImports = ssrImports.join('\n')
|
|
76
89
|
|
|
77
90
|
const registryEntries = blocks.map(block => {
|
|
78
91
|
const slugVar = block.slug.replace(/-/g, '_')
|
|
@@ -124,6 +137,9 @@ import type { BlockConfig, BlockCategory } from '${convertCorePath('@/core/types
|
|
|
124
137
|
|
|
125
138
|
${fieldImports}
|
|
126
139
|
|
|
140
|
+
// Direct component imports for SSR (no React.lazy, no Suspense needed)
|
|
141
|
+
${ssrComponentImports}
|
|
142
|
+
|
|
127
143
|
export const BLOCK_REGISTRY: Record<string, BlockConfig> = {
|
|
128
144
|
${registryEntries}
|
|
129
145
|
}
|
|
@@ -141,6 +157,19 @@ ${blocks.map(block => {
|
|
|
141
157
|
}).join(',\n')}
|
|
142
158
|
}
|
|
143
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Direct-imported block components for SSR rendering
|
|
162
|
+
* No React.lazy, no Suspense — HTML is fully visible without JS.
|
|
163
|
+
* Use with SSRPageRenderer for public pages where SEO and no-JS rendering matter.
|
|
164
|
+
*/
|
|
165
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
166
|
+
export const BLOCK_COMPONENTS_SSR: Record<string, React.ComponentType<any>> = {
|
|
167
|
+
${blocks.map(block => {
|
|
168
|
+
const slugVar = block.slug.replace(/-/g, '_')
|
|
169
|
+
return ` '${block.slug}': ${slugVar}_component`
|
|
170
|
+
}).join(',\n')}
|
|
171
|
+
}
|
|
172
|
+
|
|
144
173
|
/**
|
|
145
174
|
* Block registry metadata
|
|
146
175
|
*/
|
|
@@ -6,6 +6,8 @@ export const BLOCK_REGISTRY: Record<string, any> = {}
|
|
|
6
6
|
|
|
7
7
|
export const BLOCK_COMPONENTS: Record<string, any> = {}
|
|
8
8
|
|
|
9
|
+
export const BLOCK_COMPONENTS_SSR: Record<string, any> = {}
|
|
10
|
+
|
|
9
11
|
export const BLOCK_METADATA = {
|
|
10
12
|
generated: new Date().toISOString(),
|
|
11
13
|
totalBlocks: 0,
|