@ossy/app 1.0.8 → 1.1.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 +113 -192
- package/cli/dev.js +100 -49
- package/cli/index.js +30 -0
- package/cli/server.js +5 -5
- package/cli/worker-entry.js +1 -1
- package/package.json +13 -10
package/cli/build.js
CHANGED
|
@@ -11,12 +11,10 @@ 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 { ensureBuildStubs } from '../scripts/ensure-build-stubs.mjs'
|
|
15
|
-
import { createRequire } from 'node:module'
|
|
16
14
|
|
|
17
|
-
const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
|
|
18
|
-
const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
|
|
19
|
-
const TASK_FILE_PATTERN = /\.task\.(mjs|cjs|js)$/
|
|
15
|
+
export const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
|
|
16
|
+
export const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
|
|
17
|
+
export const TASK_FILE_PATTERN = /\.task\.(mjs|cjs|js)$/
|
|
20
18
|
const RESOURCE_TEMPLATE_FILE_PATTERN = /\.resource\.js$/
|
|
21
19
|
|
|
22
20
|
/** Written next to `*.resource.js` under `src/resource-templates/` when that dir exists. */
|
|
@@ -57,6 +55,11 @@ export const OSSY_GEN_PAGES_BASENAME = 'pages.generated.jsx'
|
|
|
57
55
|
export const OSSY_GEN_API_BASENAME = 'api.generated.js'
|
|
58
56
|
export const OSSY_GEN_TASKS_BASENAME = 'tasks.generated.js'
|
|
59
57
|
|
|
58
|
+
/** Bundled Node entries consumed by copied `build/server.js` / `build/worker.js`. */
|
|
59
|
+
export const OSSY_PAGES_SERVER_BUNDLE = 'pages.bundle.js'
|
|
60
|
+
export const OSSY_API_SERVER_BUNDLE = 'api.bundle.js'
|
|
61
|
+
export const OSSY_TASKS_SERVER_BUNDLE = 'tasks.bundle.js'
|
|
62
|
+
|
|
60
63
|
/** Per-page client entries: `hydrate-<pageId>.jsx` under `.ossy/` */
|
|
61
64
|
const HYDRATE_STUB_PREFIX = 'hydrate-'
|
|
62
65
|
const HYDRATE_STUB_SUFFIX = '.jsx'
|
|
@@ -144,65 +147,55 @@ export function writeResourceTemplatesBarrelIfPresent ({ cwd = process.cwd(), lo
|
|
|
144
147
|
}
|
|
145
148
|
|
|
146
149
|
/**
|
|
147
|
-
*
|
|
148
|
-
* Server builds pass `nodeExternals: true` so `dependencies` stay importable from Node at runtime.
|
|
150
|
+
* Rollup plugins for Node-side bundles (pages / API / tasks): externals + Babel JSX.
|
|
149
151
|
*/
|
|
150
|
-
export function
|
|
151
|
-
|
|
152
|
-
apiSourcePath,
|
|
153
|
-
middlewareSourcePath,
|
|
154
|
-
configSourcePath,
|
|
155
|
-
nodeEnv,
|
|
156
|
-
preferBuiltins = true,
|
|
157
|
-
copyPublicFrom,
|
|
158
|
-
buildPath,
|
|
159
|
-
}) {
|
|
160
|
-
const plugins = [
|
|
161
|
-
replace({
|
|
162
|
-
preventAssignment: true,
|
|
163
|
-
delimiters: ['%%', '%%'],
|
|
164
|
-
'@ossy/pages/source-file': pagesGeneratedPath,
|
|
165
|
-
}),
|
|
152
|
+
export function createOssyAppBundlePlugins ({ nodeEnv }) {
|
|
153
|
+
return [
|
|
166
154
|
replace({
|
|
167
155
|
preventAssignment: true,
|
|
168
|
-
|
|
169
|
-
'@ossy/api/source-file': apiSourcePath,
|
|
156
|
+
'process.env.NODE_ENV': JSON.stringify(nodeEnv),
|
|
170
157
|
}),
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
158
|
+
json(),
|
|
159
|
+
nodeExternals({
|
|
160
|
+
deps: true,
|
|
161
|
+
devDeps: false,
|
|
162
|
+
peerDeps: true,
|
|
163
|
+
packagePath: path.join(process.cwd(), 'package.json'),
|
|
175
164
|
}),
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
'
|
|
165
|
+
resolveCommonJsDependencies(),
|
|
166
|
+
resolveDependencies({ preferBuiltins: true }),
|
|
167
|
+
babel({
|
|
168
|
+
babelHelpers: 'bundled',
|
|
169
|
+
extensions: ['.jsx', '.tsx'],
|
|
170
|
+
presets: ['@babel/preset-react'],
|
|
180
171
|
}),
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Rollup plugins for browser hydrate bundles.
|
|
177
|
+
*/
|
|
178
|
+
export function createOssyClientRollupPlugins ({ nodeEnv, copyPublicFrom, buildPath }) {
|
|
179
|
+
const plugins = [
|
|
181
180
|
replace({
|
|
182
181
|
preventAssignment: true,
|
|
183
182
|
'process.env.NODE_ENV': JSON.stringify(nodeEnv),
|
|
184
183
|
}),
|
|
185
184
|
json(),
|
|
186
|
-
]
|
|
187
|
-
|
|
188
|
-
plugins.push(
|
|
189
185
|
nodeExternals({
|
|
190
186
|
deps: true,
|
|
191
187
|
devDeps: false,
|
|
192
188
|
peerDeps: true,
|
|
193
189
|
packagePath: path.join(process.cwd(), 'package.json'),
|
|
194
|
-
})
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
plugins.push(
|
|
190
|
+
}),
|
|
198
191
|
resolveCommonJsDependencies(),
|
|
199
|
-
resolveDependencies({ preferBuiltins }),
|
|
192
|
+
resolveDependencies({ preferBuiltins: false }),
|
|
200
193
|
babel({
|
|
201
194
|
babelHelpers: 'bundled',
|
|
202
195
|
extensions: ['.jsx', '.tsx'],
|
|
203
196
|
presets: ['@babel/preset-react'],
|
|
204
|
-
})
|
|
205
|
-
|
|
197
|
+
}),
|
|
198
|
+
]
|
|
206
199
|
if (copyPublicFrom && fs.existsSync(copyPublicFrom)) {
|
|
207
200
|
plugins.push(
|
|
208
201
|
copy({
|
|
@@ -213,25 +206,43 @@ export function createOssyRollupPlugins ({
|
|
|
213
206
|
return plugins
|
|
214
207
|
}
|
|
215
208
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
209
|
+
/** Bundles a single Node ESM file (inline dynamic imports) for SSR / API / tasks. */
|
|
210
|
+
export async function bundleOssyNodeEntry ({ inputPath, outputFile, nodeEnv }) {
|
|
211
|
+
const bundle = await rollup({
|
|
212
|
+
input: inputPath,
|
|
213
|
+
plugins: createOssyAppBundlePlugins({ nodeEnv }),
|
|
214
|
+
})
|
|
215
|
+
await bundle.write({
|
|
216
|
+
file: outputFile,
|
|
217
|
+
format: 'esm',
|
|
218
|
+
inlineDynamicImports: true,
|
|
219
|
+
})
|
|
220
|
+
await bundle.close()
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Copies framework runtime into `build/`: server, worker entry, middleware & config snapshots.
|
|
225
|
+
* `build/server.js` imports `./middleware.js`, `./config.js`, `./.ossy/*.bundle.js` next to it.
|
|
226
|
+
*/
|
|
227
|
+
export function copyOssyAppRuntime ({
|
|
228
|
+
scriptDir,
|
|
229
|
+
buildPath,
|
|
230
|
+
middlewareSourcePath,
|
|
231
|
+
configSourcePath,
|
|
232
|
+
}) {
|
|
233
|
+
for (const name of ['server.js', 'proxy-internal.js']) {
|
|
234
|
+
fs.copyFileSync(path.join(scriptDir, name), path.join(buildPath, name))
|
|
229
235
|
}
|
|
230
|
-
|
|
231
|
-
|
|
236
|
+
fs.copyFileSync(middlewareSourcePath, path.join(buildPath, 'middleware.js'))
|
|
237
|
+
fs.copyFileSync(configSourcePath, path.join(buildPath, 'config.js'))
|
|
238
|
+
fs.copyFileSync(path.join(scriptDir, 'worker-entry.js'), path.join(buildPath, 'worker.js'))
|
|
239
|
+
fs.copyFileSync(path.join(scriptDir, 'worker-runtime.js'), path.join(buildPath, 'worker-runtime.js'))
|
|
232
240
|
}
|
|
233
241
|
|
|
234
|
-
|
|
242
|
+
/**
|
|
243
|
+
* Recursively lists files under `srcDir` whose basename matches `filePattern` (e.g. `/\.api\.js$/`).
|
|
244
|
+
*/
|
|
245
|
+
export function discoverFilesByPattern (srcDir, filePattern) {
|
|
235
246
|
const dir = path.resolve(srcDir)
|
|
236
247
|
if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
|
|
237
248
|
return []
|
|
@@ -242,7 +253,7 @@ export function discoverTaskFiles(srcDir) {
|
|
|
242
253
|
for (const e of entries) {
|
|
243
254
|
const full = path.join(d, e.name)
|
|
244
255
|
if (e.isDirectory()) walk(full)
|
|
245
|
-
else if (
|
|
256
|
+
else if (filePattern.test(e.name)) files.push(full)
|
|
246
257
|
}
|
|
247
258
|
}
|
|
248
259
|
walk(dir)
|
|
@@ -294,7 +305,7 @@ export function generateApiModule ({ generatedPath, apiFiles }) {
|
|
|
294
305
|
export function resolveApiSource ({ srcDir, buildPath }) {
|
|
295
306
|
ensureOssyGeneratedDir(buildPath)
|
|
296
307
|
const generatedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_API_BASENAME)
|
|
297
|
-
const apiFiles =
|
|
308
|
+
const apiFiles = discoverFilesByPattern(srcDir, API_FILE_PATTERN)
|
|
298
309
|
fs.writeFileSync(
|
|
299
310
|
generatedPath,
|
|
300
311
|
generateApiModule({ generatedPath, apiFiles })
|
|
@@ -336,43 +347,20 @@ export function generateTaskModule ({ generatedPath, taskFiles }) {
|
|
|
336
347
|
}
|
|
337
348
|
|
|
338
349
|
/**
|
|
339
|
-
*
|
|
350
|
+
* Writes `build/.ossy/tasks.generated.js` and returns its path (stable Rollup input; empty when no task files).
|
|
340
351
|
*/
|
|
341
|
-
export function resolveTaskSource ({ srcDir,
|
|
342
|
-
const defaultStub = path.resolve(scriptDir, 'tasks.js')
|
|
352
|
+
export function resolveTaskSource ({ srcDir, buildPath }) {
|
|
343
353
|
ensureOssyGeneratedDir(buildPath)
|
|
344
354
|
const generatedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_TASKS_BASENAME)
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
355
|
+
const taskFiles = discoverFilesByPattern(srcDir, TASK_FILE_PATTERN)
|
|
356
|
+
fs.writeFileSync(
|
|
357
|
+
generatedPath,
|
|
358
|
+
generateTaskModule({
|
|
349
359
|
generatedPath,
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
)
|
|
355
|
-
return { taskSourcePath: generatedPath, taskOverviewFiles: taskFiles, usedGenerated: true }
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return { taskSourcePath: defaultStub, taskOverviewFiles: [], usedGenerated: false }
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
export function discoverPageFiles(srcDir) {
|
|
362
|
-
if (!fs.existsSync(srcDir) || !fs.statSync(srcDir).isDirectory()) {
|
|
363
|
-
return []
|
|
364
|
-
}
|
|
365
|
-
const files = []
|
|
366
|
-
const walk = (d) => {
|
|
367
|
-
const entries = fs.readdirSync(d, { withFileTypes: true })
|
|
368
|
-
for (const e of entries) {
|
|
369
|
-
const full = path.join(d, e.name)
|
|
370
|
-
if (e.isDirectory()) walk(full)
|
|
371
|
-
else if (PAGE_FILE_PATTERN.test(e.name)) files.push(full)
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
walk(srcDir)
|
|
375
|
-
return files.sort()
|
|
360
|
+
taskFiles,
|
|
361
|
+
})
|
|
362
|
+
)
|
|
363
|
+
return { taskSourcePath: generatedPath, taskOverviewFiles: taskFiles }
|
|
376
364
|
}
|
|
377
365
|
|
|
378
366
|
export function filePathToRoute(filePath, srcDir) {
|
|
@@ -510,65 +498,6 @@ export function generatePagesModule (pageFiles, srcDir, generatedPath) {
|
|
|
510
498
|
return lines.join('\n')
|
|
511
499
|
}
|
|
512
500
|
|
|
513
|
-
export async function discoverModulePageFiles({ configPath }) {
|
|
514
|
-
if (!configPath || !fs.existsSync(configPath)) return []
|
|
515
|
-
try {
|
|
516
|
-
// Try a cheap static parse first so we don't depend on the config file being
|
|
517
|
-
// importable (configs often import theme/template modules that may not be
|
|
518
|
-
// resolvable in the build-time node context).
|
|
519
|
-
const cfgSource = fs.readFileSync(configPath, 'utf8')
|
|
520
|
-
const modules = []
|
|
521
|
-
|
|
522
|
-
// pagesModules: ['a', "b"]
|
|
523
|
-
const arrMatch = cfgSource.match(/pagesModules\s*:\s*\[([^\]]*)\]/m)
|
|
524
|
-
if (arrMatch?.[1]) {
|
|
525
|
-
const body = arrMatch[1]
|
|
526
|
-
const re = /['"]([^'"]+)['"]/g
|
|
527
|
-
let m
|
|
528
|
-
while ((m = re.exec(body)) !== null) modules.push(m[1])
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// pagesModule: 'a'
|
|
532
|
-
if (modules.length === 0) {
|
|
533
|
-
const singleMatch = cfgSource.match(/pagesModule\s*:\s*['"]([^'"]+)['"]/m)
|
|
534
|
-
if (singleMatch?.[1]) modules.push(singleMatch[1])
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
if (modules.length) {
|
|
538
|
-
const req = createRequire(path.resolve(process.cwd(), 'package.json'))
|
|
539
|
-
const files = []
|
|
540
|
-
for (const name of modules) {
|
|
541
|
-
const pkgJsonPath = req.resolve(`${name}/package.json`)
|
|
542
|
-
const pkgDir = path.dirname(pkgJsonPath)
|
|
543
|
-
const modulePagesDir = path.join(pkgDir, 'src', 'pages')
|
|
544
|
-
files.push(...discoverPageFiles(modulePagesDir))
|
|
545
|
-
}
|
|
546
|
-
return files
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
const mod = await import(url.pathToFileURL(configPath))
|
|
550
|
-
const cfg = mod?.default ?? mod ?? {}
|
|
551
|
-
const modules2 = Array.isArray(cfg.pagesModules)
|
|
552
|
-
? cfg.pagesModules
|
|
553
|
-
: (typeof cfg.pagesModule === 'string' ? [cfg.pagesModule] : [])
|
|
554
|
-
|
|
555
|
-
if (!modules2.length) return []
|
|
556
|
-
|
|
557
|
-
const req = createRequire(path.resolve(process.cwd(), 'package.json'))
|
|
558
|
-
const files = []
|
|
559
|
-
for (const name of modules2) {
|
|
560
|
-
const pkgJsonPath = req.resolve(`${name}/package.json`)
|
|
561
|
-
const pkgDir = path.dirname(pkgJsonPath)
|
|
562
|
-
const modulePagesDir = path.join(pkgDir, 'src', 'pages')
|
|
563
|
-
files.push(...discoverPageFiles(modulePagesDir))
|
|
564
|
-
}
|
|
565
|
-
return files
|
|
566
|
-
} catch (e) {
|
|
567
|
-
console.warn('[@ossy/app][build] pagesModules config could not be loaded; continuing without modules')
|
|
568
|
-
return []
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
|
|
572
501
|
export function parsePagesFromSource(filePath) {
|
|
573
502
|
try {
|
|
574
503
|
const content = fs.readFileSync(filePath, 'utf8')
|
|
@@ -665,8 +594,7 @@ export const build = async (cliArgs) => {
|
|
|
665
594
|
const buildPath = path.resolve('build')
|
|
666
595
|
const srcDir = path.resolve('src')
|
|
667
596
|
const configPath = path.resolve(options['--config'] || 'src/config.js');
|
|
668
|
-
const pageFiles =
|
|
669
|
-
const modulePageFiles = await discoverModulePageFiles({ configPath })
|
|
597
|
+
const pageFiles = discoverFilesByPattern(srcDir, PAGE_FILE_PATTERN)
|
|
670
598
|
|
|
671
599
|
resetOssyBuildDir(buildPath)
|
|
672
600
|
|
|
@@ -674,14 +602,13 @@ export const build = async (cliArgs) => {
|
|
|
674
602
|
|
|
675
603
|
const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
|
|
676
604
|
|
|
677
|
-
const allPageFiles = [...pageFiles, ...modulePageFiles]
|
|
678
605
|
fs.writeFileSync(
|
|
679
606
|
pagesGeneratedPath,
|
|
680
|
-
generatePagesModule(
|
|
607
|
+
generatePagesModule(pageFiles, srcDir, pagesGeneratedPath)
|
|
681
608
|
)
|
|
682
609
|
const ossyDir = ossyGeneratedDir(buildPath)
|
|
683
|
-
writePageHydrateStubs(
|
|
684
|
-
const clientHydrateInput = buildClientHydrateInput(
|
|
610
|
+
writePageHydrateStubs(pageFiles, srcDir, ossyDir)
|
|
611
|
+
const clientHydrateInput = buildClientHydrateInput(pageFiles, srcDir, ossyDir)
|
|
685
612
|
|
|
686
613
|
const {
|
|
687
614
|
apiSourcePath: resolvedApi,
|
|
@@ -694,8 +621,6 @@ export const build = async (cliArgs) => {
|
|
|
694
621
|
let middlewareSourcePath = path.resolve('src/middleware.js');
|
|
695
622
|
const publicDir = path.resolve('public')
|
|
696
623
|
|
|
697
|
-
const inputServer = path.resolve(scriptDir, 'server.js')
|
|
698
|
-
|
|
699
624
|
printBuildOverview({
|
|
700
625
|
pagesSourcePath: pagesGeneratedPath,
|
|
701
626
|
apiSourcePath,
|
|
@@ -712,40 +637,38 @@ export const build = async (cliArgs) => {
|
|
|
712
637
|
? configPath
|
|
713
638
|
: path.resolve(scriptDir, 'default-config.js')
|
|
714
639
|
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
middlewareSourcePath,
|
|
719
|
-
configSourcePath,
|
|
720
|
-
nodeEnv: 'production',
|
|
721
|
-
buildPath,
|
|
722
|
-
}
|
|
640
|
+
const pagesBundlePath = path.join(ossyDir, OSSY_PAGES_SERVER_BUNDLE)
|
|
641
|
+
const apiBundlePath = path.join(ossyDir, OSSY_API_SERVER_BUNDLE)
|
|
642
|
+
const tasksBundlePath = path.join(ossyDir, OSSY_TASKS_SERVER_BUNDLE)
|
|
723
643
|
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
644
|
+
await bundleOssyNodeEntry({
|
|
645
|
+
inputPath: pagesGeneratedPath,
|
|
646
|
+
outputFile: pagesBundlePath,
|
|
647
|
+
nodeEnv: 'production',
|
|
728
648
|
})
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
649
|
+
await bundleOssyNodeEntry({
|
|
650
|
+
inputPath: apiSourcePath,
|
|
651
|
+
outputFile: apiBundlePath,
|
|
652
|
+
nodeEnv: 'production',
|
|
733
653
|
})
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
entryFileNames ({ name }) {
|
|
740
|
-
return name === 'server' ? 'server.js' : '[name].js'
|
|
741
|
-
},
|
|
742
|
-
assetFileNames: '[name][extname]',
|
|
654
|
+
const { taskSourcePath } = resolveTaskSource({ srcDir, buildPath })
|
|
655
|
+
await bundleOssyNodeEntry({
|
|
656
|
+
inputPath: taskSourcePath,
|
|
657
|
+
outputFile: tasksBundlePath,
|
|
658
|
+
nodeEnv: 'production',
|
|
743
659
|
})
|
|
744
|
-
await serverBundle.close()
|
|
745
660
|
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
661
|
+
copyOssyAppRuntime({
|
|
662
|
+
scriptDir,
|
|
663
|
+
buildPath,
|
|
664
|
+
middlewareSourcePath,
|
|
665
|
+
configSourcePath,
|
|
666
|
+
})
|
|
667
|
+
|
|
668
|
+
const clientPlugins = createOssyClientRollupPlugins({
|
|
669
|
+
nodeEnv: 'production',
|
|
670
|
+
copyPublicFrom: publicDir,
|
|
671
|
+
buildPath,
|
|
749
672
|
})
|
|
750
673
|
|
|
751
674
|
if (Object.keys(clientHydrateInput).length > 0) {
|
|
@@ -769,7 +692,5 @@ export const build = async (cliArgs) => {
|
|
|
769
692
|
await clientBundle.close()
|
|
770
693
|
}
|
|
771
694
|
|
|
772
|
-
ensureBuildStubs(buildPath)
|
|
773
|
-
|
|
774
695
|
console.log('[@ossy/app][build] Finished');
|
|
775
696
|
};
|
package/cli/dev.js
CHANGED
|
@@ -3,18 +3,26 @@ import url from 'url';
|
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import {
|
|
5
5
|
printBuildOverview,
|
|
6
|
-
|
|
6
|
+
discoverFilesByPattern,
|
|
7
|
+
PAGE_FILE_PATTERN,
|
|
7
8
|
generatePagesModule,
|
|
8
|
-
discoverModulePageFiles,
|
|
9
9
|
resolveApiSource,
|
|
10
|
+
resolveTaskSource,
|
|
10
11
|
resetOssyBuildDir,
|
|
11
|
-
|
|
12
|
+
bundleOssyNodeEntry,
|
|
13
|
+
copyOssyAppRuntime,
|
|
14
|
+
createOssyAppBundlePlugins,
|
|
15
|
+
createOssyClientRollupPlugins,
|
|
12
16
|
writePageHydrateStubs,
|
|
13
17
|
buildClientHydrateInput,
|
|
14
18
|
clientHydrateIdForPage,
|
|
15
19
|
ossyGeneratedDir,
|
|
16
20
|
OSSY_GEN_PAGES_BASENAME,
|
|
17
21
|
OSSY_GEN_API_BASENAME,
|
|
22
|
+
OSSY_GEN_TASKS_BASENAME,
|
|
23
|
+
OSSY_PAGES_SERVER_BUNDLE,
|
|
24
|
+
OSSY_API_SERVER_BUNDLE,
|
|
25
|
+
OSSY_TASKS_SERVER_BUNDLE,
|
|
18
26
|
writeResourceTemplatesBarrelIfPresent,
|
|
19
27
|
resourceTemplatesDir,
|
|
20
28
|
OSSY_RESOURCE_TEMPLATES_OUT,
|
|
@@ -37,23 +45,20 @@ export const dev = async (cliArgs) => {
|
|
|
37
45
|
const buildPath = path.resolve('build')
|
|
38
46
|
const srcDir = path.resolve('src')
|
|
39
47
|
const configPath = path.resolve(options['--config'] || 'src/config.js');
|
|
40
|
-
const pageFiles =
|
|
41
|
-
const modulePageFiles = await discoverModulePageFiles({ configPath })
|
|
48
|
+
const pageFiles = discoverFilesByPattern(srcDir, PAGE_FILE_PATTERN)
|
|
42
49
|
|
|
43
50
|
resetOssyBuildDir(buildPath)
|
|
44
51
|
|
|
45
52
|
writeResourceTemplatesBarrelIfPresent({ cwd: process.cwd(), log: true })
|
|
46
53
|
|
|
47
|
-
const allPageFiles = [...pageFiles, ...modulePageFiles]
|
|
48
54
|
const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
|
|
49
55
|
fs.writeFileSync(
|
|
50
56
|
pagesGeneratedPath,
|
|
51
|
-
generatePagesModule(
|
|
57
|
+
generatePagesModule(pageFiles, srcDir, pagesGeneratedPath)
|
|
52
58
|
)
|
|
53
|
-
const effectivePagesSource = pagesGeneratedPath
|
|
54
59
|
const ossyDir = ossyGeneratedDir(buildPath)
|
|
55
|
-
writePageHydrateStubs(
|
|
56
|
-
const clientHydrateInput = buildClientHydrateInput(
|
|
60
|
+
writePageHydrateStubs(pageFiles, srcDir, ossyDir)
|
|
61
|
+
const clientHydrateInput = buildClientHydrateInput(pageFiles, srcDir, ossyDir)
|
|
57
62
|
|
|
58
63
|
const {
|
|
59
64
|
apiSourcePath: resolvedApi,
|
|
@@ -63,13 +68,12 @@ export const dev = async (cliArgs) => {
|
|
|
63
68
|
buildPath,
|
|
64
69
|
})
|
|
65
70
|
let apiSourcePath = resolvedApi
|
|
71
|
+
resolveTaskSource({ srcDir, buildPath })
|
|
66
72
|
let middlewareSourcePath = path.resolve(options['--middleware-source'] || 'src/middleware.js');
|
|
67
73
|
const publicDir = path.resolve('public')
|
|
68
74
|
|
|
69
|
-
const inputServer = path.resolve(scriptDir, 'server.js')
|
|
70
|
-
|
|
71
75
|
printBuildOverview({
|
|
72
|
-
pagesSourcePath:
|
|
76
|
+
pagesSourcePath: pagesGeneratedPath,
|
|
73
77
|
apiSourcePath,
|
|
74
78
|
apiOverviewFiles,
|
|
75
79
|
configPath,
|
|
@@ -84,37 +88,43 @@ export const dev = async (cliArgs) => {
|
|
|
84
88
|
? configPath
|
|
85
89
|
: path.resolve(scriptDir, 'default-config.js')
|
|
86
90
|
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
const pagesBundlePath = path.join(ossyDir, OSSY_PAGES_SERVER_BUNDLE)
|
|
92
|
+
const apiBundlePath = path.join(ossyDir, OSSY_API_SERVER_BUNDLE)
|
|
93
|
+
const tasksBundlePath = path.join(ossyDir, OSSY_TASKS_SERVER_BUNDLE)
|
|
94
|
+
const tasksGeneratedPath = path.join(ossyDir, OSSY_GEN_TASKS_BASENAME)
|
|
95
|
+
|
|
96
|
+
const runNodeBundles = async () => {
|
|
97
|
+
await bundleOssyNodeEntry({
|
|
98
|
+
inputPath: pagesGeneratedPath,
|
|
99
|
+
outputFile: pagesBundlePath,
|
|
100
|
+
nodeEnv: 'development',
|
|
101
|
+
})
|
|
102
|
+
await bundleOssyNodeEntry({
|
|
103
|
+
inputPath: apiSourcePath,
|
|
104
|
+
outputFile: apiBundlePath,
|
|
105
|
+
nodeEnv: 'development',
|
|
106
|
+
})
|
|
107
|
+
await bundleOssyNodeEntry({
|
|
108
|
+
inputPath: tasksGeneratedPath,
|
|
109
|
+
outputFile: tasksBundlePath,
|
|
110
|
+
nodeEnv: 'development',
|
|
111
|
+
})
|
|
112
|
+
copyOssyAppRuntime({
|
|
113
|
+
scriptDir,
|
|
114
|
+
buildPath,
|
|
115
|
+
middlewareSourcePath,
|
|
116
|
+
configSourcePath,
|
|
117
|
+
})
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
|
|
97
|
-
...sharedPluginOpts,
|
|
98
|
-
preferBuiltins: true,
|
|
99
|
-
copyPublicFrom: publicDir,
|
|
100
|
-
})
|
|
120
|
+
await runNodeBundles()
|
|
101
121
|
|
|
102
|
-
const clientPlugins =
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
const clientPlugins = createOssyClientRollupPlugins({
|
|
123
|
+
nodeEnv: 'development',
|
|
124
|
+
copyPublicFrom: publicDir,
|
|
125
|
+
buildPath,
|
|
105
126
|
})
|
|
106
127
|
|
|
107
|
-
const serverOutput = {
|
|
108
|
-
dir: buildPath,
|
|
109
|
-
format: 'esm',
|
|
110
|
-
preserveModules: true,
|
|
111
|
-
preserveModulesRoot: path.dirname(inputServer),
|
|
112
|
-
entryFileNames ({ name }) {
|
|
113
|
-
return name === 'server' ? 'server.js' : '[name].js'
|
|
114
|
-
},
|
|
115
|
-
assetFileNames: '[name][extname]',
|
|
116
|
-
}
|
|
117
|
-
|
|
118
128
|
const clientOutput = {
|
|
119
129
|
dir: buildPath,
|
|
120
130
|
format: 'esm',
|
|
@@ -169,12 +179,37 @@ export const dev = async (cliArgs) => {
|
|
|
169
179
|
}
|
|
170
180
|
}
|
|
171
181
|
|
|
182
|
+
const nodeWatchOpts = { watch: { clearScreen: false } }
|
|
172
183
|
const watchConfigs = [
|
|
173
184
|
{
|
|
174
|
-
input:
|
|
175
|
-
output:
|
|
176
|
-
|
|
177
|
-
|
|
185
|
+
input: pagesGeneratedPath,
|
|
186
|
+
output: {
|
|
187
|
+
file: pagesBundlePath,
|
|
188
|
+
format: 'esm',
|
|
189
|
+
inlineDynamicImports: true,
|
|
190
|
+
},
|
|
191
|
+
plugins: createOssyAppBundlePlugins({ nodeEnv: 'development' }),
|
|
192
|
+
...nodeWatchOpts,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
input: apiSourcePath,
|
|
196
|
+
output: {
|
|
197
|
+
file: apiBundlePath,
|
|
198
|
+
format: 'esm',
|
|
199
|
+
inlineDynamicImports: true,
|
|
200
|
+
},
|
|
201
|
+
plugins: createOssyAppBundlePlugins({ nodeEnv: 'development' }),
|
|
202
|
+
...nodeWatchOpts,
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
input: tasksGeneratedPath,
|
|
206
|
+
output: {
|
|
207
|
+
file: tasksBundlePath,
|
|
208
|
+
format: 'esm',
|
|
209
|
+
inlineDynamicImports: true,
|
|
210
|
+
},
|
|
211
|
+
plugins: createOssyAppBundlePlugins({ nodeEnv: 'development' }),
|
|
212
|
+
...nodeWatchOpts,
|
|
178
213
|
},
|
|
179
214
|
]
|
|
180
215
|
if (Object.keys(clientHydrateInput).length > 0) {
|
|
@@ -198,11 +233,17 @@ export const dev = async (cliArgs) => {
|
|
|
198
233
|
console.log(`[@ossy/app][dev] Built in ${event.duration}ms`)
|
|
199
234
|
}
|
|
200
235
|
if (event.code === 'END') {
|
|
236
|
+
copyOssyAppRuntime({
|
|
237
|
+
scriptDir,
|
|
238
|
+
buildPath,
|
|
239
|
+
middlewareSourcePath,
|
|
240
|
+
configSourcePath,
|
|
241
|
+
})
|
|
201
242
|
scheduleRestart()
|
|
202
243
|
}
|
|
203
244
|
})
|
|
204
245
|
|
|
205
|
-
const
|
|
246
|
+
const regenApiGenerated = () => {
|
|
206
247
|
if (options['--api-source']) return
|
|
207
248
|
resolveApiSource({
|
|
208
249
|
srcDir,
|
|
@@ -214,23 +255,33 @@ export const dev = async (cliArgs) => {
|
|
|
214
255
|
}
|
|
215
256
|
}
|
|
216
257
|
|
|
258
|
+
const regenTasksGenerated = () => {
|
|
259
|
+
resolveTaskSource({ srcDir, buildPath })
|
|
260
|
+
if (fs.existsSync(tasksGeneratedPath) && typeof watcher?.invalidate === 'function') {
|
|
261
|
+
watcher.invalidate(tasksGeneratedPath)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
217
265
|
fs.watch(srcDir, { recursive: true }, (eventType, filename) => {
|
|
218
266
|
if (!filename) return
|
|
219
267
|
if (/\.page\.(jsx?|tsx?)$/.test(filename)) {
|
|
220
|
-
const
|
|
268
|
+
const refreshedPageFiles = discoverFilesByPattern(srcDir, PAGE_FILE_PATTERN)
|
|
221
269
|
const regenPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
|
|
222
|
-
fs.writeFileSync(regenPath, generatePagesModule(
|
|
223
|
-
writePageHydrateStubs(
|
|
270
|
+
fs.writeFileSync(regenPath, generatePagesModule(refreshedPageFiles, srcDir, regenPath))
|
|
271
|
+
writePageHydrateStubs(refreshedPageFiles, srcDir, ossyDir)
|
|
224
272
|
if (typeof watcher?.invalidate === 'function') {
|
|
225
273
|
watcher.invalidate(regenPath)
|
|
226
|
-
for (const f of
|
|
274
|
+
for (const f of refreshedPageFiles) {
|
|
227
275
|
const hid = clientHydrateIdForPage(f, srcDir)
|
|
228
276
|
watcher.invalidate(path.join(ossyDir, `hydrate-${hid}.jsx`))
|
|
229
277
|
}
|
|
230
278
|
}
|
|
231
279
|
}
|
|
232
280
|
if (/\.api\.(mjs|cjs|js)$/.test(filename)) {
|
|
233
|
-
|
|
281
|
+
regenApiGenerated()
|
|
282
|
+
}
|
|
283
|
+
if (/\.task\.(mjs|cjs|js)$/.test(filename)) {
|
|
284
|
+
regenTasksGenerated()
|
|
234
285
|
}
|
|
235
286
|
const norm = filename.replace(/\\/g, '/')
|
|
236
287
|
if (/\.resource\.js$/.test(norm) && norm.includes('resource-templates/')) {
|
package/cli/index.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { build } from './build.js'
|
|
3
|
+
import { dev } from './dev.js'
|
|
4
|
+
|
|
5
|
+
const [,, command, ...restArgs] = process.argv
|
|
6
|
+
|
|
7
|
+
if (!command) {
|
|
8
|
+
console.error(
|
|
9
|
+
'[@ossy/app] No command provided. Usage: app dev | build'
|
|
10
|
+
)
|
|
11
|
+
process.exit(1)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const run = async () => {
|
|
15
|
+
if (command === 'dev') {
|
|
16
|
+
await dev(restArgs)
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
if (command === 'build') {
|
|
20
|
+
await build(restArgs)
|
|
21
|
+
return
|
|
22
|
+
}
|
|
23
|
+
console.error(`[@ossy/app] Unknown command: ${command}`)
|
|
24
|
+
process.exit(1)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
run().catch((err) => {
|
|
28
|
+
console.error(err)
|
|
29
|
+
process.exit(1)
|
|
30
|
+
})
|
package/cli/server.js
CHANGED
|
@@ -8,14 +8,14 @@ import { prerenderToNodeStream } from 'react-dom/static'
|
|
|
8
8
|
import { ProxyInternal } from './proxy-internal.js'
|
|
9
9
|
import cookieParser from 'cookie-parser'
|
|
10
10
|
|
|
11
|
-
import pages from '
|
|
12
|
-
import ApiRoutes from '
|
|
13
|
-
import Middleware from '
|
|
14
|
-
import configModule from '
|
|
11
|
+
import pages from './.ossy/pages.bundle.js'
|
|
12
|
+
import ApiRoutes from './.ossy/api.bundle.js'
|
|
13
|
+
import Middleware from './middleware.js'
|
|
14
|
+
import configModule from './config.js'
|
|
15
15
|
|
|
16
16
|
const buildTimeConfig = configModule?.default ?? configModule ?? {}
|
|
17
17
|
|
|
18
|
-
/**
|
|
18
|
+
/** API bundle default may be an empty array. */
|
|
19
19
|
const apiRouteList = ApiRoutes ?? []
|
|
20
20
|
const pageList = pages ?? []
|
|
21
21
|
|
package/cli/worker-entry.js
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ossy/app",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"source": "./src/index.js",
|
|
6
6
|
"main": "./src/index.js",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"bin": {
|
|
9
|
+
"app": "./cli/index.js"
|
|
10
|
+
},
|
|
8
11
|
"scripts": {
|
|
9
12
|
"build": "echo Building not required",
|
|
10
13
|
"test": "node --experimental-vm-modules ../node_modules/jest/bin/jest.js --verbose",
|
|
@@ -24,14 +27,14 @@
|
|
|
24
27
|
"@babel/eslint-parser": "^7.15.8",
|
|
25
28
|
"@babel/preset-react": "^7.26.3",
|
|
26
29
|
"@babel/register": "^7.25.9",
|
|
27
|
-
"@ossy/connected-components": "^1.0
|
|
28
|
-
"@ossy/design-system": "^1.0
|
|
29
|
-
"@ossy/pages": "^1.0
|
|
30
|
-
"@ossy/router": "^1.0
|
|
31
|
-
"@ossy/router-react": "^1.0
|
|
32
|
-
"@ossy/sdk": "^1.0
|
|
33
|
-
"@ossy/sdk-react": "^1.0
|
|
34
|
-
"@ossy/themes": "^1.0
|
|
30
|
+
"@ossy/connected-components": "^1.1.0",
|
|
31
|
+
"@ossy/design-system": "^1.1.0",
|
|
32
|
+
"@ossy/pages": "^1.1.0",
|
|
33
|
+
"@ossy/router": "^1.1.0",
|
|
34
|
+
"@ossy/router-react": "^1.1.0",
|
|
35
|
+
"@ossy/sdk": "^1.1.0",
|
|
36
|
+
"@ossy/sdk-react": "^1.1.0",
|
|
37
|
+
"@ossy/themes": "^1.1.0",
|
|
35
38
|
"@rollup/plugin-alias": "^6.0.0",
|
|
36
39
|
"@rollup/plugin-babel": "6.1.0",
|
|
37
40
|
"@rollup/plugin-commonjs": "^29.0.0",
|
|
@@ -64,5 +67,5 @@
|
|
|
64
67
|
"README.md",
|
|
65
68
|
"tsconfig.json"
|
|
66
69
|
],
|
|
67
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "5977a77f97776131077a848081098ab6ec4cf837"
|
|
68
71
|
}
|