@ossy/app 1.7.0 → 1.9.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/cli/build.js +15 -14
- package/cli/dev.js +14 -4
- package/cli/prerender-pages.js +101 -0
- package/cli/server.js +3 -48
- package/package.json +10 -10
- package/cli/tasks.js +0 -2
- package/cli/temp.js +0 -3
package/cli/build.js
CHANGED
|
@@ -11,6 +11,7 @@ import nodeExternals from 'rollup-plugin-node-externals'
|
|
|
11
11
|
import copy from 'rollup-plugin-copy';
|
|
12
12
|
import replace from '@rollup/plugin-replace';
|
|
13
13
|
import arg from 'arg'
|
|
14
|
+
import { writePrerenderedPages } from './prerender-pages.js'
|
|
14
15
|
|
|
15
16
|
export const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
|
|
16
17
|
export const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
|
|
@@ -55,11 +56,10 @@ export const OSSY_GEN_PAGES_BASENAME = 'pages.generated.jsx'
|
|
|
55
56
|
export const OSSY_GEN_API_BASENAME = 'api.generated.js'
|
|
56
57
|
export const OSSY_GEN_TASKS_BASENAME = 'tasks.generated.js'
|
|
57
58
|
|
|
58
|
-
/** Bundled
|
|
59
|
-
export const
|
|
59
|
+
/** Bundled pages + React for build-time prerender only (not loaded by `server.js`). */
|
|
60
|
+
export const OSSY_PAGES_PRERENDER_BUNDLE = 'pages.prerender.bundle.js'
|
|
60
61
|
export const OSSY_API_SERVER_BUNDLE = 'api.bundle.js'
|
|
61
62
|
export const OSSY_TASKS_SERVER_BUNDLE = 'tasks.bundle.js'
|
|
62
|
-
export const OSSY_CONFIG_RUNTIME_BASENAME = 'config.runtime.js'
|
|
63
63
|
export const OSSY_MIDDLEWARE_RUNTIME_BASENAME = 'middleware.runtime.js'
|
|
64
64
|
|
|
65
65
|
/** Per-page client entries: `hydrate-<pageId>.jsx` under `.ossy/` */
|
|
@@ -223,16 +223,10 @@ export async function bundleOssyNodeEntry ({ inputPath, outputFile, nodeEnv }) {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
|
-
* Re-exports
|
|
227
|
-
* relative imports (copying those files into `build/` would break them).
|
|
226
|
+
* Re-exports middleware via `file:` URL so `src/middleware.js` can keep relative imports.
|
|
228
227
|
*/
|
|
229
|
-
export function writeAppRuntimeShims ({
|
|
230
|
-
const cfgHref = url.pathToFileURL(path.resolve(configSourcePath)).href
|
|
228
|
+
export function writeAppRuntimeShims ({ middlewareSourcePath, ossyDir }) {
|
|
231
229
|
const mwHref = url.pathToFileURL(path.resolve(middlewareSourcePath)).href
|
|
232
|
-
fs.writeFileSync(
|
|
233
|
-
path.join(ossyDir, OSSY_CONFIG_RUNTIME_BASENAME),
|
|
234
|
-
`// Generated by @ossy/app — do not edit\nexport { default } from '${cfgHref}'\n`
|
|
235
|
-
)
|
|
236
230
|
fs.writeFileSync(
|
|
237
231
|
path.join(ossyDir, OSSY_MIDDLEWARE_RUNTIME_BASENAME),
|
|
238
232
|
`// Generated by @ossy/app — do not edit\nexport { default } from '${mwHref}'\n`
|
|
@@ -241,7 +235,7 @@ export function writeAppRuntimeShims ({ configSourcePath, middlewareSourcePath,
|
|
|
241
235
|
|
|
242
236
|
/**
|
|
243
237
|
* Copies framework runtime into `build/`: server, worker entry, proxy.
|
|
244
|
-
*
|
|
238
|
+
* Middleware loads via `./.ossy/middleware.runtime.js`.
|
|
245
239
|
*/
|
|
246
240
|
export function copyOssyAppRuntime ({ scriptDir, buildPath }) {
|
|
247
241
|
for (const name of ['server.js', 'proxy-internal.js']) {
|
|
@@ -656,7 +650,7 @@ export const build = async (cliArgs) => {
|
|
|
656
650
|
? configPath
|
|
657
651
|
: path.resolve(scriptDir, 'default-config.js')
|
|
658
652
|
|
|
659
|
-
const pagesBundlePath = path.join(ossyDir,
|
|
653
|
+
const pagesBundlePath = path.join(ossyDir, OSSY_PAGES_PRERENDER_BUNDLE)
|
|
660
654
|
const apiBundlePath = path.join(ossyDir, OSSY_API_SERVER_BUNDLE)
|
|
661
655
|
const tasksBundlePath = path.join(ossyDir, OSSY_TASKS_SERVER_BUNDLE)
|
|
662
656
|
|
|
@@ -678,7 +672,6 @@ export const build = async (cliArgs) => {
|
|
|
678
672
|
})
|
|
679
673
|
|
|
680
674
|
writeAppRuntimeShims({
|
|
681
|
-
configSourcePath,
|
|
682
675
|
middlewareSourcePath,
|
|
683
676
|
ossyDir,
|
|
684
677
|
})
|
|
@@ -711,5 +704,13 @@ export const build = async (cliArgs) => {
|
|
|
711
704
|
await clientBundle.close()
|
|
712
705
|
}
|
|
713
706
|
|
|
707
|
+
if (pageFiles.length > 0) {
|
|
708
|
+
await writePrerenderedPages({
|
|
709
|
+
pagesBundlePath,
|
|
710
|
+
configSourcePath,
|
|
711
|
+
publicDir: path.join(buildPath, 'public'),
|
|
712
|
+
})
|
|
713
|
+
}
|
|
714
|
+
|
|
714
715
|
console.log('[@ossy/app][build] Finished');
|
|
715
716
|
};
|
package/cli/dev.js
CHANGED
|
@@ -21,13 +21,14 @@ import {
|
|
|
21
21
|
OSSY_GEN_PAGES_BASENAME,
|
|
22
22
|
OSSY_GEN_API_BASENAME,
|
|
23
23
|
OSSY_GEN_TASKS_BASENAME,
|
|
24
|
-
|
|
24
|
+
OSSY_PAGES_PRERENDER_BUNDLE,
|
|
25
25
|
OSSY_API_SERVER_BUNDLE,
|
|
26
26
|
OSSY_TASKS_SERVER_BUNDLE,
|
|
27
27
|
writeResourceTemplatesBarrelIfPresent,
|
|
28
28
|
resourceTemplatesDir,
|
|
29
29
|
OSSY_RESOURCE_TEMPLATES_OUT,
|
|
30
30
|
} from './build.js';
|
|
31
|
+
import { writePrerenderedPages } from './prerender-pages.js'
|
|
31
32
|
import { watch } from 'rollup';
|
|
32
33
|
import arg from 'arg'
|
|
33
34
|
import { spawn } from 'node:child_process'
|
|
@@ -89,7 +90,7 @@ export const dev = async (cliArgs) => {
|
|
|
89
90
|
? configPath
|
|
90
91
|
: path.resolve(scriptDir, 'default-config.js')
|
|
91
92
|
|
|
92
|
-
const pagesBundlePath = path.join(ossyDir,
|
|
93
|
+
const pagesBundlePath = path.join(ossyDir, OSSY_PAGES_PRERENDER_BUNDLE)
|
|
93
94
|
const apiBundlePath = path.join(ossyDir, OSSY_API_SERVER_BUNDLE)
|
|
94
95
|
const tasksBundlePath = path.join(ossyDir, OSSY_TASKS_SERVER_BUNDLE)
|
|
95
96
|
const tasksGeneratedPath = path.join(ossyDir, OSSY_GEN_TASKS_BASENAME)
|
|
@@ -111,7 +112,6 @@ export const dev = async (cliArgs) => {
|
|
|
111
112
|
nodeEnv: 'development',
|
|
112
113
|
})
|
|
113
114
|
writeAppRuntimeShims({
|
|
114
|
-
configSourcePath,
|
|
115
115
|
middlewareSourcePath,
|
|
116
116
|
ossyDir,
|
|
117
117
|
})
|
|
@@ -235,11 +235,21 @@ export const dev = async (cliArgs) => {
|
|
|
235
235
|
}
|
|
236
236
|
if (event.code === 'END') {
|
|
237
237
|
writeAppRuntimeShims({
|
|
238
|
-
configSourcePath,
|
|
239
238
|
middlewareSourcePath,
|
|
240
239
|
ossyDir,
|
|
241
240
|
})
|
|
242
241
|
copyOssyAppRuntime({ scriptDir, buildPath })
|
|
242
|
+
if (pageFiles.length > 0) {
|
|
243
|
+
try {
|
|
244
|
+
await writePrerenderedPages({
|
|
245
|
+
pagesBundlePath,
|
|
246
|
+
configSourcePath,
|
|
247
|
+
publicDir: path.join(buildPath, 'public'),
|
|
248
|
+
})
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error('[@ossy/app][dev] Prerender failed', err)
|
|
251
|
+
}
|
|
252
|
+
}
|
|
243
253
|
scheduleRestart()
|
|
244
254
|
}
|
|
245
255
|
})
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import url from 'url'
|
|
3
|
+
import fs from 'fs'
|
|
4
|
+
import { BuildPage } from './render-page.task.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Maps an app route path to the file path express.static will serve for that URL
|
|
8
|
+
* (`/` → `public/index.html`, `/a/b` → `public/a/b/index.html`).
|
|
9
|
+
*/
|
|
10
|
+
export function staticHtmlPathForRoute (routePath, publicDir) {
|
|
11
|
+
const p = typeof routePath === 'string' ? routePath : '/'
|
|
12
|
+
if (p === '/' || p === '') {
|
|
13
|
+
return path.join(publicDir, 'index.html')
|
|
14
|
+
}
|
|
15
|
+
const segments = p.replace(/^\//, '').split('/').filter(Boolean)
|
|
16
|
+
return path.join(publicDir, ...segments, 'index.html')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function pathIsPrerenderable (routePath) {
|
|
20
|
+
if (typeof routePath !== 'string') return false
|
|
21
|
+
if (!routePath.startsWith('/') || routePath.includes(':')) return false
|
|
22
|
+
return true
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** Mirrors server `resolveAppConfig` with static defaults (no cookies / session). */
|
|
26
|
+
export function buildPrerenderAppConfig ({
|
|
27
|
+
buildTimeConfig,
|
|
28
|
+
pageList,
|
|
29
|
+
activeRouteId,
|
|
30
|
+
urlPath,
|
|
31
|
+
}) {
|
|
32
|
+
const pages = pageList.map((page) => {
|
|
33
|
+
const entry = {
|
|
34
|
+
id: page?.id,
|
|
35
|
+
path: page?.path,
|
|
36
|
+
}
|
|
37
|
+
if (activeRouteId != null && page?.id === activeRouteId) {
|
|
38
|
+
entry.element = page?.element
|
|
39
|
+
}
|
|
40
|
+
return entry
|
|
41
|
+
})
|
|
42
|
+
return {
|
|
43
|
+
...buildTimeConfig,
|
|
44
|
+
url: urlPath,
|
|
45
|
+
theme: buildTimeConfig.theme || 'light',
|
|
46
|
+
isAuthenticated: false,
|
|
47
|
+
workspaceId: buildTimeConfig.workspaceId,
|
|
48
|
+
apiUrl: buildTimeConfig.apiUrl,
|
|
49
|
+
pages,
|
|
50
|
+
sidebarPrimaryCollapsed: false,
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* After client bundles and `public/` exist, writes one HTML file per static page
|
|
56
|
+
* so express.static can serve them without runtime React rendering.
|
|
57
|
+
*/
|
|
58
|
+
export async function writePrerenderedPages ({
|
|
59
|
+
pagesBundlePath,
|
|
60
|
+
configSourcePath,
|
|
61
|
+
publicDir,
|
|
62
|
+
}) {
|
|
63
|
+
const cfgHref = url.pathToFileURL(path.resolve(configSourcePath)).href
|
|
64
|
+
const pagesHref = url.pathToFileURL(path.resolve(pagesBundlePath)).href
|
|
65
|
+
|
|
66
|
+
const configModule = await import(cfgHref)
|
|
67
|
+
const pagesModule = await import(pagesHref)
|
|
68
|
+
|
|
69
|
+
const buildTimeConfig = configModule?.default ?? configModule ?? {}
|
|
70
|
+
const pageList = pagesModule?.default ?? []
|
|
71
|
+
|
|
72
|
+
for (const route of pageList) {
|
|
73
|
+
if (!route?.element) continue
|
|
74
|
+
if (!pathIsPrerenderable(route.path)) {
|
|
75
|
+
console.warn(
|
|
76
|
+
`[@ossy/app][prerender] Skipping "${route.id}" (path not prerenderable: ${JSON.stringify(route.path)})`
|
|
77
|
+
)
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const appConfig = buildPrerenderAppConfig({
|
|
82
|
+
buildTimeConfig,
|
|
83
|
+
pageList,
|
|
84
|
+
activeRouteId: route.id,
|
|
85
|
+
urlPath: route.path,
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
const html = await BuildPage.handle({
|
|
89
|
+
route,
|
|
90
|
+
appConfig,
|
|
91
|
+
isDevReloadEnabled: false,
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const outPath = staticHtmlPathForRoute(route.path, publicDir)
|
|
95
|
+
fs.mkdirSync(path.dirname(outPath), { recursive: true })
|
|
96
|
+
fs.writeFileSync(outPath, html, 'utf8')
|
|
97
|
+
console.log(
|
|
98
|
+
`[@ossy/app][prerender] ${route.path} → ${path.relative(process.cwd(), outPath)}`
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
}
|
package/cli/server.js
CHANGED
|
@@ -5,18 +5,12 @@ import morgan from 'morgan'
|
|
|
5
5
|
import { Router as OssyRouter } from '@ossy/router'
|
|
6
6
|
import { ProxyInternal } from './proxy-internal.js'
|
|
7
7
|
import cookieParser from 'cookie-parser'
|
|
8
|
-
import { BuildPage } from './render-page.task.js'
|
|
9
8
|
|
|
10
|
-
import pages from './.ossy/pages.bundle.js'
|
|
11
9
|
import ApiRoutes from './.ossy/api.bundle.js'
|
|
12
10
|
import Middleware from './.ossy/middleware.runtime.js'
|
|
13
|
-
import configModule from './.ossy/config.runtime.js'
|
|
14
|
-
|
|
15
|
-
const buildTimeConfig = configModule?.default ?? configModule ?? {}
|
|
16
11
|
|
|
17
12
|
/** API bundle default may be an empty array. */
|
|
18
13
|
const apiRouteList = ApiRoutes ?? []
|
|
19
|
-
const pageList = pages ?? []
|
|
20
14
|
|
|
21
15
|
const app = express();
|
|
22
16
|
|
|
@@ -108,34 +102,9 @@ const middleware = [
|
|
|
108
102
|
app.use(middleware)
|
|
109
103
|
|
|
110
104
|
const Router = OssyRouter.of({
|
|
111
|
-
pages:
|
|
105
|
+
pages: apiRouteList,
|
|
112
106
|
})
|
|
113
107
|
|
|
114
|
-
function resolveAppConfig ({ req, buildTimeConfig, activeRouteId }) {
|
|
115
|
-
const userAppSettings = req.userAppSettings || {}
|
|
116
|
-
const pages = pageList.map((page) => {
|
|
117
|
-
const entry = {
|
|
118
|
-
id: page?.id,
|
|
119
|
-
path: page?.path,
|
|
120
|
-
}
|
|
121
|
-
if (activeRouteId != null && page?.id === activeRouteId) {
|
|
122
|
-
entry.element = page?.element
|
|
123
|
-
}
|
|
124
|
-
return entry
|
|
125
|
-
})
|
|
126
|
-
return {
|
|
127
|
-
...buildTimeConfig,
|
|
128
|
-
url: req.originalUrl,
|
|
129
|
-
theme: userAppSettings.theme || buildTimeConfig.theme || 'light',
|
|
130
|
-
isAuthenticated: req.isAuthenticated || false,
|
|
131
|
-
workspaceId: userAppSettings.workspaceId || buildTimeConfig.workspaceId,
|
|
132
|
-
apiUrl: buildTimeConfig.apiUrl,
|
|
133
|
-
pages,
|
|
134
|
-
/** Primary app shell sidebar: icon rail when true (persisted in `x-ossy-user-settings`). */
|
|
135
|
-
sidebarPrimaryCollapsed: userAppSettings.sidebarPrimaryCollapsed === true,
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
108
|
app.all('*all', (req, res) => {
|
|
140
109
|
const pathname = req.originalUrl
|
|
141
110
|
|
|
@@ -147,23 +116,9 @@ app.all('*all', (req, res) => {
|
|
|
147
116
|
return
|
|
148
117
|
}
|
|
149
118
|
|
|
150
|
-
|
|
151
|
-
res.status(404).send('Not found')
|
|
152
|
-
return
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const appConfig = resolveAppConfig({
|
|
156
|
-
req,
|
|
157
|
-
buildTimeConfig,
|
|
158
|
-
activeRouteId: route.id,
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
BuildPage.handle({ route, appConfig, isDevReloadEnabled })
|
|
162
|
-
.then(html => { res.send(html) })
|
|
163
|
-
.catch(err => { res.send(err) })
|
|
164
|
-
|
|
119
|
+
res.status(404).send('Not found')
|
|
165
120
|
})
|
|
166
121
|
|
|
167
122
|
app.listen(port, () => {
|
|
168
123
|
console.log(`[@ossy/app][server] Running on http://localhost:${port}`);
|
|
169
|
-
});
|
|
124
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/app",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
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.
|
|
31
|
-
"@ossy/design-system": "^1.
|
|
32
|
-
"@ossy/pages": "^1.
|
|
33
|
-
"@ossy/router": "^1.
|
|
34
|
-
"@ossy/router-react": "^1.
|
|
35
|
-
"@ossy/sdk": "^1.
|
|
36
|
-
"@ossy/sdk-react": "^1.
|
|
37
|
-
"@ossy/themes": "^1.
|
|
30
|
+
"@ossy/connected-components": "^1.9.0",
|
|
31
|
+
"@ossy/design-system": "^1.9.0",
|
|
32
|
+
"@ossy/pages": "^1.9.0",
|
|
33
|
+
"@ossy/router": "^1.9.0",
|
|
34
|
+
"@ossy/router-react": "^1.9.0",
|
|
35
|
+
"@ossy/sdk": "^1.9.0",
|
|
36
|
+
"@ossy/sdk-react": "^1.9.0",
|
|
37
|
+
"@ossy/themes": "^1.9.0",
|
|
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": "9be5f444e4cd530e29be0193fc0e7fd8da0bc995"
|
|
71
71
|
}
|
package/cli/tasks.js
DELETED
package/cli/temp.js
DELETED