@ossy/app 1.11.5 → 1.11.6
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 +2 -4
- package/cli/build.js +93 -37
- package/cli/dev.js +1 -1
- package/cli/pages.runtime.mjs +4 -29
- package/cli/prerender-react.task.js +2 -2
- package/cli/render-page.task.js +34 -7
- package/cli/server.js +6 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -21,11 +21,9 @@ export const metadata = { path: { en: '/about', sv: '/om' } }
|
|
|
21
21
|
export default () => <h1>About</h1>
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
During `dev` / `build`, the tooling writes **JSON manifests** under **`build/.ossy/`**: **`pages.generated.json`** (after compile: route ids, paths, `sourceFile`, merged `metadata`, and **`module`** — a `page-modules/<id>.mjs` path used for lazy `import()` in the browser and on SSR), **`pages.bundle.json`** (compiled module index), plus the same pattern for API and tasks. Small **`*.runtime.mjs`** loaders (copied from `@ossy/app`) load the app shell; **`pages.runtime.mjs`** exports the route table from **`pages.generated.json`** only. The server exposes compiled page modules at **`/__ossy/page-modules/`** for same-origin dynamic imports.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
**Client JS (per-page):** For each `*.page.jsx`, the build emits **`build/.ossy/hydrate-<pageId>.jsx`** → **`public/static/hydrate-<pageId>.js`**. The HTML for a request only loads the hydrate script for the **current** route (full document navigation), so other pages’ components are not part of that entry. React and shared dependencies still go into hashed shared chunks. The inline config (`window.__INITIAL_APP_CONFIG__`) no longer includes the full `pages` list—only request-time fields (theme, `apiUrl`, etc.).
|
|
26
|
+
**Client JS (per-page):** For each `*.page.jsx`, the build emits **`build/.ossy/hydrate-<pageId>.jsx`** → **`public/static/<pageId>.js`**. The HTML for a request only loads the hydrate script for the **current** route (full document navigation), so other pages’ components are not part of that entry. React and shared dependencies still go into hashed shared chunks. The inline config (`window.__INITIAL_APP_CONFIG__`) no longer includes the full `pages` list—only request-time fields (theme, `apiUrl`, etc.).
|
|
29
27
|
|
|
30
28
|
Add `src/config.js` for workspace and theme:
|
|
31
29
|
|
package/cli/build.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import url from 'url';
|
|
3
3
|
import fs from 'fs';
|
|
4
|
+
import { pathToFileURL } from 'node:url'
|
|
4
5
|
import { rollup } from 'rollup';
|
|
5
6
|
import babel from '@rollup/plugin-babel';
|
|
6
7
|
import { nodeResolve as resolveDependencies } from '@rollup/plugin-node-resolve'
|
|
@@ -67,6 +68,9 @@ export const OSSY_API_RUNTIME_BASENAME = 'api.runtime.mjs'
|
|
|
67
68
|
export const OSSY_TASKS_RUNTIME_BASENAME = 'tasks.runtime.mjs'
|
|
68
69
|
|
|
69
70
|
export const OSSY_PAGE_MODULES_DIRNAME = 'page-modules'
|
|
71
|
+
|
|
72
|
+
/** Express serves compiled page modules here for browser `import()`. Must match `server.js`. */
|
|
73
|
+
export const OSSY_PAGE_MODULE_WEB_PREFIX = '/__ossy/page-modules'
|
|
70
74
|
/** Tiny Rollup inputs that re-export `metadata` so per-page server bundles keep i18n paths. */
|
|
71
75
|
export const OSSY_PAGE_SERVER_ENTRIES_DIRNAME = 'page-server-entries'
|
|
72
76
|
export const OSSY_API_MODULES_DIRNAME = 'api-modules'
|
|
@@ -385,7 +389,8 @@ export async function compilePageServerModules ({
|
|
|
385
389
|
for (const f of pageFiles) {
|
|
386
390
|
const pageId = clientHydrateIdForPage(f, srcDir)
|
|
387
391
|
const safeId = String(pageId).replace(/[^a-zA-Z0-9_-]+/g, '-') || 'page'
|
|
388
|
-
const
|
|
392
|
+
const relPath = pageServerModuleRelPath(f, srcDir)
|
|
393
|
+
const outName = path.posix.basename(relPath)
|
|
389
394
|
const outFile = path.join(modsDir, outName)
|
|
390
395
|
const stubPath = path.join(entriesDir, `${safeId}.mjs`)
|
|
391
396
|
writePageServerRollupEntry({ pageAbsPath: f, stubPath })
|
|
@@ -398,7 +403,7 @@ export async function compilePageServerModules ({
|
|
|
398
403
|
})
|
|
399
404
|
bundlePages.push({
|
|
400
405
|
id: pageId,
|
|
401
|
-
module:
|
|
406
|
+
module: relPath,
|
|
402
407
|
})
|
|
403
408
|
}
|
|
404
409
|
return bundlePages
|
|
@@ -448,6 +453,50 @@ export async function compileTaskServerModules ({ taskFiles, ossyDir, nodeEnv, o
|
|
|
448
453
|
return modules
|
|
449
454
|
}
|
|
450
455
|
|
|
456
|
+
/**
|
|
457
|
+
* Merges compiled `metadata` + `module` into `pages.generated.json` (same order as `pageBundleList`).
|
|
458
|
+
* Enables lazy `import()` in the browser and Node without putting `Component` on the route object.
|
|
459
|
+
*/
|
|
460
|
+
export async function enrichPagesGeneratedManifest ({
|
|
461
|
+
ossyDir,
|
|
462
|
+
pagesGeneratedPath,
|
|
463
|
+
pageBundleList,
|
|
464
|
+
}) {
|
|
465
|
+
if (!pageBundleList?.length || !fs.existsSync(pagesGeneratedPath)) return
|
|
466
|
+
const raw = JSON.parse(fs.readFileSync(pagesGeneratedPath, 'utf8'))
|
|
467
|
+
const basePages = raw?.pages
|
|
468
|
+
if (!Array.isArray(basePages) || basePages.length !== pageBundleList.length) {
|
|
469
|
+
throw new Error(
|
|
470
|
+
'[@ossy/app] pages.generated.json page count must match compiled page modules (re-run build).'
|
|
471
|
+
)
|
|
472
|
+
}
|
|
473
|
+
const pages = []
|
|
474
|
+
for (let i = 0; i < basePages.length; i++) {
|
|
475
|
+
const abs = path.join(ossyDir, pageBundleList[i].module)
|
|
476
|
+
const mod = await import(pathToFileURL(abs).href)
|
|
477
|
+
const meta = mod?.metadata && typeof mod.metadata === 'object' ? mod.metadata : {}
|
|
478
|
+
const derived = { id: basePages[i].id, path: basePages[i].path }
|
|
479
|
+
const merged = {
|
|
480
|
+
...derived,
|
|
481
|
+
...meta,
|
|
482
|
+
sourceFile: basePages[i].sourceFile,
|
|
483
|
+
module: pageBundleList[i].module,
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
JSON.stringify(merged)
|
|
487
|
+
} catch {
|
|
488
|
+
pages.push({
|
|
489
|
+
...derived,
|
|
490
|
+
sourceFile: basePages[i].sourceFile,
|
|
491
|
+
module: pageBundleList[i].module,
|
|
492
|
+
})
|
|
493
|
+
continue
|
|
494
|
+
}
|
|
495
|
+
pages.push(merged)
|
|
496
|
+
}
|
|
497
|
+
writeOssyJson(pagesGeneratedPath, { version: raw.version ?? 1, pages })
|
|
498
|
+
}
|
|
499
|
+
|
|
451
500
|
/**
|
|
452
501
|
* Writes `pages.bundle.json`, `api.bundle.json`, `tasks.bundle.json` by Rollup-compiling each source module.
|
|
453
502
|
*/
|
|
@@ -477,6 +526,11 @@ export async function compileOssyNodeArtifacts ({
|
|
|
477
526
|
version: 1,
|
|
478
527
|
modules: taskModuleList,
|
|
479
528
|
})
|
|
529
|
+
await enrichPagesGeneratedManifest({
|
|
530
|
+
ossyDir,
|
|
531
|
+
pagesGeneratedPath: path.join(ossyDir, OSSY_GEN_PAGES_BASENAME),
|
|
532
|
+
pageBundleList,
|
|
533
|
+
})
|
|
480
534
|
}
|
|
481
535
|
|
|
482
536
|
export function filePathToRoute(filePath, srcDir) {
|
|
@@ -489,7 +543,7 @@ export function filePathToRoute(filePath, srcDir) {
|
|
|
489
543
|
}
|
|
490
544
|
|
|
491
545
|
/**
|
|
492
|
-
* Basename for `/static
|
|
546
|
+
* Basename for `/static/<id>.js` (per-page client bundle) must match `route.id` after `metadata` is merged in `toPage`
|
|
493
547
|
* (`{ ...derived, ...metadata }`). Uses a light `metadata` scan when possible.
|
|
494
548
|
*/
|
|
495
549
|
export function clientHydrateIdForPage (pageAbsPath, srcDir) {
|
|
@@ -507,6 +561,13 @@ export function clientHydrateIdForPage (pageAbsPath, srcDir) {
|
|
|
507
561
|
return idMatch ? idMatch[1] : derived.id
|
|
508
562
|
}
|
|
509
563
|
|
|
564
|
+
/** Posix path relative to `build/.ossy/` for the compiled server/browser page module. */
|
|
565
|
+
export function pageServerModuleRelPath (pageAbsPath, srcDir) {
|
|
566
|
+
const pageId = clientHydrateIdForPage(pageAbsPath, srcDir)
|
|
567
|
+
const safeId = String(pageId).replace(/[^a-zA-Z0-9_-]+/g, '-') || 'page'
|
|
568
|
+
return `${OSSY_PAGE_MODULES_DIRNAME}/${safeId}.mjs`
|
|
569
|
+
}
|
|
570
|
+
|
|
510
571
|
export function pageSourceExportsMetadata (pageAbsPath) {
|
|
511
572
|
try {
|
|
512
573
|
const src = fs.readFileSync(pageAbsPath, 'utf8')
|
|
@@ -539,37 +600,35 @@ export function writePageServerRollupEntry ({ pageAbsPath, stubPath }) {
|
|
|
539
600
|
}
|
|
540
601
|
|
|
541
602
|
/**
|
|
542
|
-
* One client entry per page:
|
|
543
|
-
* Keeps the same `toPage` shape as `pages.runtime.mjs` + manifests so SSR and client trees match.
|
|
603
|
+
* One client entry per page: `import()` the compiled page module URL, then hydrates the document.
|
|
544
604
|
*/
|
|
545
605
|
export function generatePageHydrateModule ({ pageAbsPath, stubAbsPath, srcDir }) {
|
|
546
|
-
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
const
|
|
606
|
+
void stubAbsPath
|
|
607
|
+
const outName = path.posix.basename(pageServerModuleRelPath(pageAbsPath, srcDir))
|
|
608
|
+
const pageImportUrl = `${OSSY_PAGE_MODULE_WEB_PREFIX}/${outName}`
|
|
609
|
+
const pageImportLiteral = JSON.stringify(pageImportUrl)
|
|
550
610
|
return [
|
|
551
611
|
'// Generated by @ossy/app — do not edit',
|
|
552
612
|
'',
|
|
553
|
-
"import React, {
|
|
613
|
+
"import React, { createElement } from 'react'",
|
|
554
614
|
"import 'react-dom'",
|
|
555
615
|
"import { hydrateRoot } from 'react-dom/client'",
|
|
556
|
-
`import * as _page from './${rel}'`,
|
|
557
616
|
'',
|
|
558
|
-
'function
|
|
559
|
-
' const
|
|
560
|
-
|
|
561
|
-
'
|
|
562
|
-
'
|
|
617
|
+
'async function main () {',
|
|
618
|
+
' const initialConfig = window.__INITIAL_APP_CONFIG__ || {}',
|
|
619
|
+
` const _page = await import(${pageImportLiteral})`,
|
|
620
|
+
' const Page = _page?.default',
|
|
621
|
+
' if (typeof Page !== \'function\') {',
|
|
622
|
+
' throw new Error(`[@ossy/app] Page must export default as a function component`)',
|
|
563
623
|
' }',
|
|
564
|
-
'
|
|
624
|
+
' const rootTree = createElement(Page, initialConfig)',
|
|
625
|
+
' hydrateRoot(document, rootTree)',
|
|
565
626
|
'}',
|
|
566
627
|
'',
|
|
567
|
-
|
|
568
|
-
'
|
|
569
|
-
|
|
570
|
-
'
|
|
571
|
-
" : React.createElement('p', null, 'Not found')",
|
|
572
|
-
'hydrateRoot(document, rootTree)',
|
|
628
|
+
'main().catch((err) => {',
|
|
629
|
+
' console.error(err)',
|
|
630
|
+
" document.body.innerHTML = '<p style=\\'font-family:sans-serif;padding:1rem\\'>Hydration failed.</p>'",
|
|
631
|
+
'})',
|
|
573
632
|
'',
|
|
574
633
|
].join('\n')
|
|
575
634
|
}
|
|
@@ -646,33 +705,30 @@ export function parsePagesFromManifestJson (manifestPath) {
|
|
|
646
705
|
const data = JSON.parse(raw)
|
|
647
706
|
const pages = data?.pages
|
|
648
707
|
if (!Array.isArray(pages)) return []
|
|
649
|
-
return pages.map((p) => ({
|
|
708
|
+
return pages.map((p) => ({
|
|
709
|
+
id: p.id,
|
|
710
|
+
path: p.path,
|
|
711
|
+
...(typeof p.module === 'string' ? { module: p.module } : {}),
|
|
712
|
+
}))
|
|
650
713
|
} catch {
|
|
651
714
|
return []
|
|
652
715
|
}
|
|
653
716
|
}
|
|
654
717
|
|
|
655
|
-
|
|
718
|
+
/**
|
|
719
|
+
* Best-effort scan of a source file for `{ id, path }` literals (e.g. `*.api.js` default export).
|
|
720
|
+
* Used only for the build dashboard API list — **not** for page discovery (`*.page.jsx` only).
|
|
721
|
+
*/
|
|
722
|
+
export function parseIdPathPairsFromFile (filePath) {
|
|
656
723
|
try {
|
|
657
724
|
const content = fs.readFileSync(filePath, 'utf8')
|
|
658
725
|
const items = []
|
|
659
|
-
// Match { id: 'x', path: '/y' } or { id: "x", path: "/y" }
|
|
660
726
|
const idPathPattern = /\{\s*id\s*:\s*['"]([^'"]*)['"]\s*,\s*path\s*:\s*['"]([^'"]*)['"]/g
|
|
661
|
-
// Match { path: '/y', element: ... } (path-first)
|
|
662
|
-
const pathElementPattern = /\{\s*path\s*:\s*['"]([^'"]*)['"]\s*,\s*element\s*:/g
|
|
663
|
-
// Match { path: { en: '/x', sv: '/y' }, ... }
|
|
664
727
|
const pathObjPattern = /\{\s*path\s*:\s*\{\s*([^}]+)\}/g
|
|
665
728
|
let m
|
|
666
729
|
while ((m = idPathPattern.exec(content)) !== null) {
|
|
667
730
|
items.push({ id: m[1], path: m[2] })
|
|
668
731
|
}
|
|
669
|
-
if (items.length === 0) {
|
|
670
|
-
while ((m = pathElementPattern.exec(content)) !== null) {
|
|
671
|
-
const p = m[1]
|
|
672
|
-
const id = p === '/' ? 'home' : p.replace(/^\//, '').replace(/\/$/, '').replace(/\//g, '-') || 'page'
|
|
673
|
-
items.push({ id, path: p })
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
732
|
if (items.length === 0) {
|
|
677
733
|
while ((m = pathObjPattern.exec(content)) !== null) {
|
|
678
734
|
const pathStr = m[1].replace(/\s/g, '').replace(/:/g, ': ')
|
|
@@ -707,7 +763,7 @@ export function getBuildOverviewSnapshot ({
|
|
|
707
763
|
|
|
708
764
|
const apiRoutes = []
|
|
709
765
|
for (const f of apiOverviewFiles) {
|
|
710
|
-
if (fs.existsSync(f)) apiRoutes.push(...
|
|
766
|
+
if (fs.existsSync(f)) apiRoutes.push(...parseIdPathPairsFromFile(f))
|
|
711
767
|
}
|
|
712
768
|
|
|
713
769
|
return { configRel, pages, apiRoutes }
|
package/cli/dev.js
CHANGED
|
@@ -132,7 +132,7 @@ export const dev = async (cliArgs) => {
|
|
|
132
132
|
entryFileNames ({ name }) {
|
|
133
133
|
if (name.startsWith('hydrate__')) {
|
|
134
134
|
const pageId = name.slice('hydrate__'.length)
|
|
135
|
-
return `static
|
|
135
|
+
return `static/${pageId}.js`
|
|
136
136
|
}
|
|
137
137
|
return 'static/[name].js'
|
|
138
138
|
},
|
package/cli/pages.runtime.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs'
|
|
2
2
|
import path from 'node:path'
|
|
3
|
-
import { fileURLToPath
|
|
4
|
-
import React from 'react'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
5
4
|
|
|
6
5
|
const __ossyDir = path.dirname(fileURLToPath(import.meta.url))
|
|
7
6
|
|
|
@@ -9,31 +8,7 @@ function readJson (name) {
|
|
|
9
8
|
return JSON.parse(fs.readFileSync(path.join(__ossyDir, name), 'utf8'))
|
|
10
9
|
}
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const def = mod?.default
|
|
15
|
-
if (typeof def === 'function') {
|
|
16
|
-
return { ...derived, ...meta, element: React.createElement(def) }
|
|
17
|
-
}
|
|
18
|
-
return { ...derived, ...meta, ...(def || {}) }
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const { pages: metaPages } = readJson('pages.generated.json')
|
|
22
|
-
const { pages: bundlePages } = readJson('pages.bundle.json')
|
|
23
|
-
|
|
24
|
-
if (metaPages.length !== bundlePages.length) {
|
|
25
|
-
throw new Error(
|
|
26
|
-
'[@ossy/app][pages.runtime] pages.generated.json and pages.bundle.json must list the same number of pages'
|
|
27
|
-
)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const out = []
|
|
31
|
-
for (let i = 0; i < metaPages.length; i++) {
|
|
32
|
-
const derived = { id: metaPages[i].id, path: metaPages[i].path }
|
|
33
|
-
const rel = bundlePages[i].module
|
|
34
|
-
const abs = path.resolve(__ossyDir, rel)
|
|
35
|
-
const mod = await import(pathToFileURL(abs).href)
|
|
36
|
-
out.push(toPage(mod, derived))
|
|
37
|
-
}
|
|
11
|
+
/** Route list from `pages.generated.json` (includes `module` for lazy `import()` after build). */
|
|
12
|
+
const { pages } = readJson('pages.generated.json')
|
|
38
13
|
|
|
39
|
-
export default
|
|
14
|
+
export default Array.isArray(pages) ? pages : []
|
|
@@ -55,7 +55,7 @@ async function bundleOneHydratePage ({
|
|
|
55
55
|
const n = chunkInfo.name
|
|
56
56
|
if (n.startsWith('hydrate__')) {
|
|
57
57
|
const pageId = n.slice('hydrate__'.length)
|
|
58
|
-
return `static
|
|
58
|
+
return `static/${pageId}.js`
|
|
59
59
|
}
|
|
60
60
|
return 'static/[name].js'
|
|
61
61
|
},
|
|
@@ -157,7 +157,7 @@ async function prerenderPagesParallel ({
|
|
|
157
157
|
|
|
158
158
|
const routesToRender = []
|
|
159
159
|
for (const route of pageList) {
|
|
160
|
-
if (!route
|
|
160
|
+
if (typeof route?.module !== 'string' || !route.module) continue
|
|
161
161
|
if (!pathIsPrerenderable(route.path)) {
|
|
162
162
|
reporter?.skipPrerender?.(
|
|
163
163
|
route.id,
|
package/cli/render-page.task.js
CHANGED
|
@@ -1,8 +1,29 @@
|
|
|
1
|
-
import
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
3
|
+
import React, { createElement } from 'react'
|
|
2
4
|
import { prerenderToNodeStream } from 'react-dom/static'
|
|
3
5
|
|
|
6
|
+
const __ossyDir = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
+
|
|
8
|
+
async function loadPageDefaultExport (route) {
|
|
9
|
+
if (typeof route?.module !== 'string' || !route.module) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`[@ossy/app][BuildPage] Route "${route?.id ?? '?'}" has no compiled module path (re-run build so pages.generated.json includes "module").`
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
const abs = path.join(__ossyDir, route.module)
|
|
15
|
+
const mod = await import(pathToFileURL(abs).href)
|
|
16
|
+
const def = mod?.default
|
|
17
|
+
if (typeof def !== 'function') {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`[@ossy/app][BuildPage] Page "${route?.id}" must export default as a function component (got ${typeof def}).`
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
return def
|
|
23
|
+
}
|
|
24
|
+
|
|
4
25
|
/**
|
|
5
|
-
* App shell config for SSR / prerender (mirrors client: theme, pages metadata, active
|
|
26
|
+
* App shell config for SSR / prerender (mirrors client: theme, pages metadata, props for the active page).
|
|
6
27
|
*/
|
|
7
28
|
export function buildPrerenderAppConfig ({
|
|
8
29
|
buildTimeConfig,
|
|
@@ -11,10 +32,11 @@ export function buildPrerenderAppConfig ({
|
|
|
11
32
|
urlPath,
|
|
12
33
|
isAuthenticated = false,
|
|
13
34
|
}) {
|
|
14
|
-
/**
|
|
35
|
+
/** `module` is the lazy import path segment (see `OSSY_PAGE_MODULE_WEB_PREFIX` in the server). */
|
|
15
36
|
const pages = pageList.map((page) => ({
|
|
16
37
|
id: page?.id,
|
|
17
38
|
path: page?.path,
|
|
39
|
+
...(typeof page?.module === 'string' ? { module: page.module } : {}),
|
|
18
40
|
}))
|
|
19
41
|
return {
|
|
20
42
|
...buildTimeConfig,
|
|
@@ -28,11 +50,15 @@ export function buildPrerenderAppConfig ({
|
|
|
28
50
|
}
|
|
29
51
|
}
|
|
30
52
|
|
|
31
|
-
/** Strips non-JSON content
|
|
53
|
+
/** Strips non-JSON content for the bootstrap script; keeps serializable route fields including `module`. */
|
|
32
54
|
export function appConfigForBootstrap (appConfig) {
|
|
33
55
|
if (!appConfig || typeof appConfig !== 'object') return appConfig
|
|
34
56
|
const pages = Array.isArray(appConfig.pages)
|
|
35
|
-
? appConfig.pages.map(({ id, path }) => ({
|
|
57
|
+
? appConfig.pages.map(({ id, path, module }) => ({
|
|
58
|
+
id,
|
|
59
|
+
path,
|
|
60
|
+
...(typeof module === 'string' ? { module } : {}),
|
|
61
|
+
}))
|
|
36
62
|
: appConfig.pages
|
|
37
63
|
return { ...appConfig, pages }
|
|
38
64
|
}
|
|
@@ -65,12 +91,13 @@ export function buildHydrationAppConfig (appConfig) {
|
|
|
65
91
|
export const BuildPage = {
|
|
66
92
|
async handle ({ route, appConfig, isDevReloadEnabled }) {
|
|
67
93
|
const hydrationConfig = buildHydrationAppConfig(appConfig)
|
|
68
|
-
const
|
|
94
|
+
const Page = await loadPageDefaultExport(route)
|
|
95
|
+
const rootElement = createElement(Page, hydrationConfig)
|
|
69
96
|
const devReloadScript = isDevReloadEnabled
|
|
70
97
|
? `(function(){try{var es=new EventSource('/__ossy_reload');es.addEventListener('reload',function(){location.reload();});}catch(e){}})();`
|
|
71
98
|
: ``
|
|
72
99
|
|
|
73
|
-
const hydrateUrl = `/static
|
|
100
|
+
const hydrateUrl = `/static/${route.id}.js`
|
|
74
101
|
const { prelude } = await prerenderToNodeStream(rootElement, {
|
|
75
102
|
bootstrapScriptContent: `window.__INITIAL_APP_CONFIG__ = ${JSON.stringify(hydrationConfig)};${devReloadScript}`,
|
|
76
103
|
bootstrapModules: [hydrateUrl],
|
package/cli/server.js
CHANGED
|
@@ -38,6 +38,7 @@ const app = express();
|
|
|
38
38
|
|
|
39
39
|
const currentDir = path.dirname(url.fileURLToPath(import.meta.url))
|
|
40
40
|
const ROOT_PATH = path.resolve(currentDir, 'public')
|
|
41
|
+
const OSSY_PAGE_MODULES_STATIC = path.resolve(currentDir, '.ossy', 'page-modules')
|
|
41
42
|
|
|
42
43
|
const isDevReloadEnabled = process.env.OSSY_DEV_RELOAD === '1'
|
|
43
44
|
const reloadClients = new Set()
|
|
@@ -121,6 +122,10 @@ const middleware = [
|
|
|
121
122
|
ProxyInternal(),
|
|
122
123
|
]
|
|
123
124
|
|
|
125
|
+
const pageModuleRouter = express.Router()
|
|
126
|
+
pageModuleRouter.use(express.static(OSSY_PAGE_MODULES_STATIC))
|
|
127
|
+
app.use('/__ossy/page-modules', pageModuleRouter)
|
|
128
|
+
|
|
124
129
|
app.use(middleware)
|
|
125
130
|
|
|
126
131
|
const apiRouter = OssyRouter.of({
|
|
@@ -155,7 +160,7 @@ app.all('*all', async (req, res) => {
|
|
|
155
160
|
}
|
|
156
161
|
|
|
157
162
|
const pageRoute = pageRouter.getPageByUrl(requestUrl)
|
|
158
|
-
if (pageRoute?.
|
|
163
|
+
if (pageRoute?.module) {
|
|
159
164
|
const appConfig = buildPrerenderAppConfig({
|
|
160
165
|
buildTimeConfig,
|
|
161
166
|
pageList: sitePageList,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/app",
|
|
3
|
-
"version": "1.11.
|
|
3
|
+
"version": "1.11.6",
|
|
4
4
|
"description": "",
|
|
5
5
|
"source": "./src/index.js",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"@babel/eslint-parser": "^7.15.8",
|
|
28
28
|
"@babel/preset-react": "^7.26.3",
|
|
29
29
|
"@babel/register": "^7.25.9",
|
|
30
|
-
"@ossy/connected-components": "^1.11.
|
|
31
|
-
"@ossy/design-system": "^1.11.
|
|
32
|
-
"@ossy/pages": "^1.11.
|
|
33
|
-
"@ossy/router": "^1.11.
|
|
34
|
-
"@ossy/router-react": "^1.11.
|
|
35
|
-
"@ossy/sdk": "^1.11.
|
|
36
|
-
"@ossy/sdk-react": "^1.11.
|
|
37
|
-
"@ossy/themes": "^1.11.
|
|
30
|
+
"@ossy/connected-components": "^1.11.6",
|
|
31
|
+
"@ossy/design-system": "^1.11.6",
|
|
32
|
+
"@ossy/pages": "^1.11.6",
|
|
33
|
+
"@ossy/router": "^1.11.6",
|
|
34
|
+
"@ossy/router-react": "^1.11.6",
|
|
35
|
+
"@ossy/sdk": "^1.11.6",
|
|
36
|
+
"@ossy/sdk-react": "^1.11.6",
|
|
37
|
+
"@ossy/themes": "^1.11.6",
|
|
38
38
|
"@rollup/plugin-alias": "^6.0.0",
|
|
39
39
|
"@rollup/plugin-babel": "6.1.0",
|
|
40
40
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"README.md",
|
|
68
68
|
"tsconfig.json"
|
|
69
69
|
],
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "f9bbe1dbd426b6ee5d07021428b900c570952ea4"
|
|
71
71
|
}
|