@ossy/app 1.11.0 → 1.11.1

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.
@@ -1,3 +1,5 @@
1
+ import util from 'node:util'
2
+
1
3
  const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']
2
4
 
3
5
  const dim = (s) => `\x1b[2m${s}\x1b[0m`
@@ -15,6 +17,13 @@ function padVisible (s, width) {
15
17
  return n >= width ? s : s + ' '.repeat(width - n)
16
18
  }
17
19
 
20
+ function truncateVisible (s, maxW) {
21
+ const plain = stripAnsi(s)
22
+ if (plain.length <= maxW) return s
23
+ const cut = Math.max(0, maxW - 1)
24
+ return plain.slice(0, cut) + '…'
25
+ }
26
+
18
27
  export function pageIdFromHydrateEntryName (entryName) {
19
28
  const p = String(entryName)
20
29
  return p.startsWith('hydrate__') ? p.slice('hydrate__'.length) : p
@@ -51,24 +60,35 @@ function rowLeadIcon (r, mode) {
51
60
  return green('✔')
52
61
  }
53
62
 
63
+ function useTty (stream) {
64
+ return (
65
+ stream.isTTY === true &&
66
+ process.env.TERM !== 'dumb' &&
67
+ process.env.CI !== 'true' &&
68
+ process.env.OSSY_PLAIN_OUTPUT !== '1'
69
+ )
70
+ }
71
+
54
72
  /**
55
- * Lerna-style live table: one row per page, hydrate + prerender columns.
56
- * TTY: redraws in place with a spinner while work runs. Non-TTY: one line per finished step.
73
+ * Merged overview + per-page progress, split layout: left = status table, right = log tail.
74
+ * TTY: single redraw block + optional console capture into the right column.
57
75
  */
58
- export function createParallelPagesReporter ({
76
+ export function createBuildDashboard ({
59
77
  scope = '@ossy/app',
78
+ mode = 'full',
60
79
  pageIds,
80
+ /** @type {Record<string, string>} route path per page id */
81
+ idToPath = {},
82
+ overview = { title: '@ossy/app', configRel: null, apiRoutes: [] },
61
83
  stream = process.stdout,
62
- /** `'full'`: hydrate + prerender columns. `'prerender-only'`: dev watch (client built separately). */
63
- mode = 'full',
64
84
  } = {}) {
65
85
  const ids = [...pageIds].sort()
66
- const maxId = Math.max(8, ...ids.map((id) => String(id).length))
67
- const tty =
68
- stream.isTTY === true &&
69
- process.env.TERM !== 'dumb' &&
70
- process.env.CI !== 'true' &&
71
- process.env.OSSY_PLAIN_OUTPUT !== '1'
86
+ const maxId = Math.max(6, ...ids.map((id) => String(id).length))
87
+ const tty = useTty(stream)
88
+ const termW = Math.max(60, stream.columns || 100)
89
+ const LEFT_W = Math.min(56, Math.max(38, Math.floor(termW * 0.42)))
90
+ const GAP = 2
91
+ const RIGHT_W = Math.max(16, termW - LEFT_W - GAP)
72
92
 
73
93
  /** @type {Map<string, { bundle: object, prerender: object }>} */
74
94
  const rows = new Map()
@@ -79,9 +99,13 @@ export function createParallelPagesReporter ({
79
99
  })
80
100
  }
81
101
 
102
+ const logBuffer = []
103
+ const MAX_LOG = 120
82
104
  let frame = 0
83
105
  let spinTimer = null
84
106
  let blockLines = 0
107
+ let captureActive = false
108
+ let savedConsole = null
85
109
 
86
110
  const anyRunning = () => {
87
111
  for (const r of rows.values()) {
@@ -90,44 +114,107 @@ export function createParallelPagesReporter ({
90
114
  return false
91
115
  }
92
116
 
93
- function ensureSpin () {
94
- if (!tty || spinTimer) return
95
- spinTimer = setInterval(() => {
96
- frame += 1
97
- redraw()
98
- }, 80)
117
+ function pushLog (line) {
118
+ const s = String(line).trim() ? String(line) : ''
119
+ if (!s) return
120
+ if (!tty) {
121
+ stream.write(`${s}\n`)
122
+ return
123
+ }
124
+ logBuffer.push(dim(s))
125
+ if (logBuffer.length > MAX_LOG) logBuffer.splice(0, logBuffer.length - MAX_LOG)
126
+ redraw()
99
127
  }
100
128
 
101
- function stopSpin () {
102
- if (spinTimer) {
103
- clearInterval(spinTimer)
104
- spinTimer = null
129
+ function leftHeaderLines () {
130
+ const out = []
131
+ out.push(bold(overview.title || `${scope} build`))
132
+ if (overview.configRel) {
133
+ out.push(`${dim('config')} ${truncateVisible(overview.configRel, LEFT_W - 10)}`)
105
134
  }
135
+ const api = overview.apiRoutes || []
136
+ if (api.length === 0) {
137
+ /* noop */
138
+ } else if (api.length <= 2) {
139
+ for (const r of api) {
140
+ const line = `${dim('api')} ${truncateVisible(`${r.id} ${r.path}`, LEFT_W - 6)}`
141
+ out.push(line)
142
+ }
143
+ } else {
144
+ out.push(`${dim('api')} ${api.length} routes`)
145
+ }
146
+ out.push(dim('─'.repeat(Math.min(LEFT_W - 2, 44))))
147
+ return out
106
148
  }
107
149
 
108
- function lineFor (id) {
150
+ function lineForPageRow (id) {
109
151
  const r = rows.get(id)
110
152
  const lead = rowLeadIcon(r, mode)
153
+ const pathStr = idToPath[id] != null ? dim(String(idToPath[id])) : ''
111
154
  const idCol = padVisible(dim(String(id)), maxId)
155
+ const pathPad = padVisible(pathStr, 14)
112
156
  const p = fmtPart(r.prerender, 'html', frame)
113
157
  if (mode === 'prerender-only') {
114
- return ` ${lead} ${dim(scope)} ${idCol} ${p}`
158
+ return ` ${lead} ${dim(scope)} ${idCol} ${pathPad} ${p}`
115
159
  }
116
160
  const b = fmtPart(r.bundle, 'hydrate', frame)
117
- return ` ${lead} ${dim(scope)} ${idCol} ${padVisible(b, 24)} ${p}`
161
+ return ` ${lead} ${dim(scope)} ${idCol} ${pathPad} ${padVisible(b, 20)} ${p}`
162
+ }
163
+
164
+ function buildLeftColumnLines () {
165
+ const head = leftHeaderLines()
166
+ const body = ids.map((id) => lineForPageRow(id))
167
+ return [...head, ...body]
168
+ }
169
+
170
+ function buildHeaderOnlyLines () {
171
+ return leftHeaderLines()
172
+ }
173
+
174
+ /** Right column row i: logs bottom-aligned to the block height */
175
+ function rightColumnLine (i, totalRows) {
176
+ const start = logBuffer.length - totalRows + i
177
+ if (start < 0 || start >= logBuffer.length) return dim('·')
178
+ return truncateVisible(logBuffer[start], RIGHT_W)
179
+ }
180
+
181
+ function paintRow (leftLine, rightLine) {
182
+ const L = padVisible(truncateVisible(leftLine, LEFT_W), LEFT_W)
183
+ const R = truncateVisible(rightLine, RIGHT_W)
184
+ return `${L}${' '.repeat(GAP)}${R}\n`
118
185
  }
119
186
 
120
187
  function redraw () {
121
188
  if (!tty) return
122
- const lines = ids.map((id) => lineFor(id))
189
+ const leftCol = buildLeftColumnLines()
190
+ const n = leftCol.length
191
+ const lines = []
192
+ for (let i = 0; i < n; i++) {
193
+ lines.push(paintRow(leftCol[i], rightColumnLine(i, n)))
194
+ }
123
195
  if (blockLines === 0) {
124
- for (const ln of lines) stream.write(`${ln}\n`)
196
+ for (const ln of lines) stream.write(ln)
125
197
  blockLines = lines.length
126
198
  return
127
199
  }
128
200
  stream.write(`\x1b[${blockLines}A`)
129
201
  for (const ln of lines) {
130
- stream.write(`\x1b[2K\r${ln}\n`)
202
+ stream.write(`\x1b[2K\r${ln}`)
203
+ }
204
+ }
205
+
206
+ function ensureSpin () {
207
+ if (!tty || spinTimer) return
208
+ spinTimer = setInterval(() => {
209
+ frame += 1
210
+ redraw()
211
+ }, 80)
212
+ }
213
+
214
+ function stopSpin () {
215
+ if (spinTimer) {
216
+ clearInterval(spinTimer)
217
+ spinTimer = null
131
218
  }
132
219
  }
133
220
 
@@ -139,7 +226,58 @@ export function createParallelPagesReporter ({
139
226
  if (err && !ok) stream.write(` ${red(String(err.message || err))}\n`)
140
227
  }
141
228
 
229
+ function beginCapture () {
230
+ if (!tty || captureActive) return
231
+ captureActive = true
232
+ savedConsole = {
233
+ log: console.log,
234
+ warn: console.warn,
235
+ info: console.info,
236
+ error: console.error,
237
+ }
238
+ const fmt = (...a) => util.format(...a)
239
+ console.log = (...a) => {
240
+ pushLog(`[log] ${fmt(...a)}`)
241
+ }
242
+ console.warn = (...a) => {
243
+ pushLog(`[warn] ${fmt(...a)}`)
244
+ }
245
+ console.info = (...a) => {
246
+ pushLog(`[info] ${fmt(...a)}`)
247
+ }
248
+ console.error = (...a) => {
249
+ const msg = fmt(...a)
250
+ pushLog(`[error] ${msg}`)
251
+ savedConsole.error(`[@ossy/app] ${msg}`)
252
+ }
253
+ }
254
+
255
+ function endCapture () {
256
+ if (!captureActive || !savedConsole) return
257
+ console.log = savedConsole.log
258
+ console.warn = savedConsole.warn
259
+ console.info = savedConsole.info
260
+ console.error = savedConsole.error
261
+ savedConsole = null
262
+ captureActive = false
263
+ }
264
+
142
265
  return {
266
+ pushLog,
267
+
268
+ /** Start optional console hijack + first paint (TTY). Plain header only when not a TTY. */
269
+ start () {
270
+ if (!tty) {
271
+ for (const ln of buildHeaderOnlyLines()) {
272
+ stream.write(`${ln}\n`)
273
+ }
274
+ stream.write('\n')
275
+ return
276
+ }
277
+ beginCapture()
278
+ redraw()
279
+ },
280
+
143
281
  startBundle (pageId) {
144
282
  if (mode === 'prerender-only') return
145
283
  const r = rows.get(pageId)
@@ -188,23 +326,18 @@ export function createParallelPagesReporter ({
188
326
  redraw()
189
327
  },
190
328
 
191
- /** Stop spinner and leave cursor below the block (TTY). */
192
- dispose () {
193
- stopSpin()
194
- if (tty && blockLines > 0) {
195
- redraw()
196
- stream.write('\n')
197
- blockLines = 0
198
- }
329
+ printSectionTitle () {
330
+ /* merged into overview.title — no-op for API compat */
199
331
  },
200
332
 
201
- printSectionTitle (title) {
333
+ dispose () {
202
334
  stopSpin()
335
+ endCapture()
203
336
  if (tty && blockLines > 0) {
337
+ redraw()
204
338
  stream.write('\n')
205
339
  blockLines = 0
206
340
  }
207
- stream.write(`\n ${bold(scope)} ${dim(title)}\n`)
208
341
  },
209
342
  }
210
343
  }
package/cli/build.js CHANGED
@@ -12,7 +12,7 @@ import copy from 'rollup-plugin-copy';
12
12
  import replace from '@rollup/plugin-replace';
13
13
  import arg from 'arg'
14
14
  import prerenderReactTask from './prerender-react.task.js'
15
- import { createParallelPagesReporter } from './build-terminal.js'
15
+ import { createBuildDashboard } from './build-terminal.js'
16
16
 
17
17
  export const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
18
18
  export const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
@@ -210,10 +210,17 @@ export function createOssyClientRollupPlugins ({ nodeEnv, copyPublicFrom, buildP
210
210
  }
211
211
 
212
212
  /** Bundles a single Node ESM file (inline dynamic imports) for SSR / API / tasks. */
213
- export async function bundleOssyNodeEntry ({ inputPath, outputFile, nodeEnv }) {
213
+ export async function bundleOssyNodeEntry ({ inputPath, outputFile, nodeEnv, onWarn }) {
214
214
  const bundle = await rollup({
215
215
  input: inputPath,
216
216
  plugins: createOssyAppBundlePlugins({ nodeEnv }),
217
+ onwarn (warning, defaultHandler) {
218
+ if (onWarn) {
219
+ onWarn(warning)
220
+ return
221
+ }
222
+ defaultHandler(warning)
223
+ },
217
224
  })
218
225
  await bundle.write({
219
226
  file: outputFile,
@@ -545,24 +552,46 @@ export function parsePagesFromSource(filePath) {
545
552
  }
546
553
  }
547
554
 
548
- export function printBuildOverview({
555
+ /**
556
+ * Same facts as the old build overview printout, for dashboards / plain logging.
557
+ */
558
+ export function getBuildOverviewSnapshot ({
549
559
  pagesSourcePath,
550
560
  apiSourcePath,
551
561
  apiOverviewFiles = [],
552
562
  configPath,
553
563
  pageFiles,
554
564
  }) {
555
- const rel = (p) => p ? path.relative(process.cwd(), p) : undefined
565
+ const rel = (p) => (p ? path.relative(process.cwd(), p) : undefined)
556
566
  const srcDir = path.resolve(process.cwd(), 'src')
557
- console.log('\n \x1b[1mBuild overview\x1b[0m')
558
- if (fs.existsSync(configPath)) {
559
- console.log(` \x1b[36mConfig:\x1b[0m ${rel(configPath)}`)
560
- }
561
- console.log(' ' + '─'.repeat(50))
567
+ const configRel = fs.existsSync(configPath) ? rel(configPath) : null
562
568
 
563
569
  const pages = pageFiles?.length
564
570
  ? pageFiles.map((f) => filePathToRoute(f, srcDir))
565
571
  : parsePagesFromSource(pagesSourcePath)
572
+
573
+ const apiFilesToScan =
574
+ apiOverviewFiles?.length > 0
575
+ ? apiOverviewFiles
576
+ : fs.existsSync(apiSourcePath)
577
+ ? [apiSourcePath]
578
+ : []
579
+ const apiRoutes = []
580
+ for (const f of apiFilesToScan) {
581
+ if (fs.existsSync(f)) apiRoutes.push(...parsePagesFromSource(f))
582
+ }
583
+
584
+ return { configRel, pages, apiRoutes }
585
+ }
586
+
587
+ export function printBuildOverview (opts) {
588
+ const { configRel, pages, apiRoutes } = getBuildOverviewSnapshot(opts)
589
+ console.log('\n \x1b[1mBuild overview\x1b[0m')
590
+ if (configRel) {
591
+ console.log(` \x1b[36mConfig:\x1b[0m ${configRel}`)
592
+ }
593
+ console.log(' ' + '─'.repeat(50))
594
+
566
595
  if (pages.length > 0) {
567
596
  console.log(' \x1b[36mRoutes:\x1b[0m')
568
597
  const maxId = Math.max(6, ...pages.map((p) => String(p.id).length))
@@ -576,16 +605,6 @@ export function printBuildOverview({
576
605
  console.log(' \x1b[33mRoutes:\x1b[0m (could not parse or empty)')
577
606
  }
578
607
 
579
- const apiFilesToScan =
580
- apiOverviewFiles?.length > 0
581
- ? apiOverviewFiles
582
- : fs.existsSync(apiSourcePath)
583
- ? [apiSourcePath]
584
- : []
585
- const apiRoutes = []
586
- for (const f of apiFilesToScan) {
587
- if (fs.existsSync(f)) apiRoutes.push(...parsePagesFromSource(f))
588
- }
589
608
  if (apiRoutes.length > 0) {
590
609
  console.log(' \x1b[36mAPI routes:\x1b[0m')
591
610
  apiRoutes.forEach((r) => {
@@ -601,10 +620,6 @@ export const build = async (cliArgs) => {
601
620
  '-c': '--config',
602
621
  }, { argv: cliArgs })
603
622
 
604
- console.log('\n \x1b[1m@ossy/app\x1b[0m \x1b[2mbuild\x1b[0m')
605
- console.log(' \x1b[2m────────────────────────────────────────\x1b[0m')
606
-
607
-
608
623
  const scriptDir = path.dirname(url.fileURLToPath(import.meta.url))
609
624
  const buildPath = path.resolve('build')
610
625
  const srcDir = path.resolve('src')
@@ -613,7 +628,10 @@ export const build = async (cliArgs) => {
613
628
 
614
629
  resetOssyBuildDir(buildPath)
615
630
 
616
- writeResourceTemplatesBarrelIfPresent({ cwd: process.cwd(), log: true })
631
+ const resourceTemplatesResult = writeResourceTemplatesBarrelIfPresent({
632
+ cwd: process.cwd(),
633
+ log: false,
634
+ })
617
635
 
618
636
  const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
619
637
 
@@ -636,14 +654,6 @@ export const build = async (cliArgs) => {
636
654
  let middlewareSourcePath = path.resolve('src/middleware.js');
637
655
  const publicDir = path.resolve('public')
638
656
 
639
- printBuildOverview({
640
- pagesSourcePath: pagesGeneratedPath,
641
- apiSourcePath,
642
- apiOverviewFiles,
643
- configPath,
644
- pageFiles,
645
- });
646
-
647
657
  if (!fs.existsSync(middlewareSourcePath)) {
648
658
  middlewareSourcePath = path.resolve(scriptDir, 'middleware.js')
649
659
  }
@@ -656,21 +666,82 @@ export const build = async (cliArgs) => {
656
666
  const apiBundlePath = path.join(ossyDir, OSSY_API_SERVER_BUNDLE)
657
667
  const tasksBundlePath = path.join(ossyDir, OSSY_TASKS_SERVER_BUNDLE)
658
668
 
669
+ const useDashboard = Object.keys(clientHydrateInput).length > 0
670
+ const overviewSnap = getBuildOverviewSnapshot({
671
+ pagesSourcePath: pagesGeneratedPath,
672
+ apiSourcePath,
673
+ apiOverviewFiles,
674
+ configPath,
675
+ pageFiles,
676
+ })
677
+ const idToPath = Object.fromEntries(
678
+ pageFiles.map((f) => [
679
+ clientHydrateIdForPage(f, srcDir),
680
+ filePathToRoute(f, srcDir).path,
681
+ ])
682
+ )
683
+ const pageIds = useDashboard
684
+ ? [...new Set(pageFiles.map((f) => clientHydrateIdForPage(f, srcDir)))].sort()
685
+ : []
686
+
687
+ let dashboard = null
688
+ if (useDashboard && pageIds.length > 0) {
689
+ dashboard = createBuildDashboard({
690
+ mode: 'full',
691
+ pageIds,
692
+ idToPath,
693
+ overview: {
694
+ title: '@ossy/app build',
695
+ configRel: overviewSnap.configRel,
696
+ apiRoutes: overviewSnap.apiRoutes,
697
+ },
698
+ })
699
+ dashboard.start()
700
+ if (resourceTemplatesResult.wrote && resourceTemplatesResult.path) {
701
+ dashboard.pushLog(
702
+ `[resource-templates] merged ${resourceTemplatesResult.count} → ${path.relative(process.cwd(), resourceTemplatesResult.path)}`
703
+ )
704
+ }
705
+ } else {
706
+ console.log('\n \x1b[1m@ossy/app\x1b[0m \x1b[2mbuild\x1b[0m')
707
+ printBuildOverview({
708
+ pagesSourcePath: pagesGeneratedPath,
709
+ apiSourcePath,
710
+ apiOverviewFiles,
711
+ configPath,
712
+ pageFiles,
713
+ })
714
+ if (resourceTemplatesResult.wrote && resourceTemplatesResult.path) {
715
+ console.log(
716
+ `[@ossy/app][resource-templates] merged ${resourceTemplatesResult.count} template(s) → ${path.relative(process.cwd(), resourceTemplatesResult.path)}`
717
+ )
718
+ }
719
+ }
720
+
721
+ const warnSink = dashboard
722
+ ? (w) => {
723
+ dashboard.pushLog(`rollup: ${w.message}`)
724
+ }
725
+ : undefined
726
+
659
727
  await bundleOssyNodeEntry({
660
728
  inputPath: pagesGeneratedPath,
661
729
  outputFile: pagesBundlePath,
662
730
  nodeEnv: 'production',
731
+ onWarn: warnSink,
663
732
  })
664
733
  await bundleOssyNodeEntry({
665
734
  inputPath: apiSourcePath,
666
735
  outputFile: apiBundlePath,
667
736
  nodeEnv: 'production',
737
+ onWarn: warnSink,
668
738
  })
669
739
  const { taskSourcePath } = resolveTaskSource({ srcDir, buildPath })
670
740
  await bundleOssyNodeEntry({
671
741
  inputPath: taskSourcePath,
672
742
  outputFile: tasksBundlePath,
673
743
  nodeEnv: 'production',
744
+ onWarn: warnSink,
674
745
  })
675
746
 
676
747
  writeAppRuntimeShims({
@@ -679,14 +750,7 @@ export const build = async (cliArgs) => {
679
750
  })
680
751
  copyOssyAppRuntime({ scriptDir, buildPath })
681
752
 
682
- if (Object.keys(clientHydrateInput).length > 0) {
683
- const pageIds = [
684
- ...new Set(pageFiles.map((f) => clientHydrateIdForPage(f, srcDir))),
685
- ].sort()
686
- const reporter = pageIds.length
687
- ? createParallelPagesReporter({ pageIds })
688
- : null
689
- reporter?.printSectionTitle('client hydrate + prerender (parallel)')
753
+ if (useDashboard && dashboard) {
690
754
  try {
691
755
  await prerenderReactTask.handler({
692
756
  op: 'runProduction',
@@ -699,13 +763,15 @@ export const build = async (cliArgs) => {
699
763
  configSourcePath,
700
764
  createClientRollupPlugins: createOssyClientRollupPlugins,
701
765
  minifyBrowserStaticChunks,
702
- reporter,
766
+ reporter: dashboard,
703
767
  })
704
768
  } finally {
705
- reporter?.dispose()
769
+ dashboard.dispose()
706
770
  }
707
771
  }
708
772
 
709
- console.log(' \x1b[2m────────────────────────────────────────\x1b[0m')
773
+ if (useDashboard && dashboard) {
774
+ console.log(' \x1b[2m────────────────────────────────────────\x1b[0m')
775
+ }
710
776
  console.log(' \x1b[32m✔\x1b[0m \x1b[1m@ossy/app\x1b[0m \x1b[2mbuild finished\x1b[0m\n')
711
777
  };
package/cli/dev.js CHANGED
@@ -3,6 +3,8 @@ import url from 'url';
3
3
  import fs from 'fs';
4
4
  import {
5
5
  printBuildOverview,
6
+ getBuildOverviewSnapshot,
7
+ filePathToRoute,
6
8
  discoverFilesByPattern,
7
9
  PAGE_FILE_PATTERN,
8
10
  generatePagesModule,
@@ -29,16 +31,13 @@ import {
29
31
  OSSY_RESOURCE_TEMPLATES_OUT,
30
32
  } from './build.js';
31
33
  import prerenderReactTask from './prerender-react.task.js'
32
- import { createParallelPagesReporter } from './build-terminal.js'
34
+ import { createBuildDashboard } from './build-terminal.js'
33
35
  import { watch } from 'rollup';
34
36
  import arg from 'arg'
35
37
  import { spawn } from 'node:child_process'
36
38
  // import inject from '@rollup/plugin-inject'
37
39
 
38
40
  export const dev = async (cliArgs) => {
39
- console.log('\n \x1b[1m@ossy/app\x1b[0m \x1b[2mdev\x1b[0m')
40
- console.log(' \x1b[2m────────────────────────────────────────\x1b[0m')
41
-
42
41
  const options = arg({
43
42
  '--config': String,
44
43
  '-c': '--config',
@@ -53,7 +52,11 @@ export const dev = async (cliArgs) => {
53
52
 
54
53
  resetOssyBuildDir(buildPath)
55
54
 
56
- writeResourceTemplatesBarrelIfPresent({ cwd: process.cwd(), log: true })
55
+ const resourceTemplatesResult = writeResourceTemplatesBarrelIfPresent({
56
+ cwd: process.cwd(),
57
+ log: false,
58
+ })
59
+ let resourceTemplatesDevLogged = false
57
60
 
58
61
  const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
59
62
  fs.writeFileSync(
@@ -76,13 +79,21 @@ export const dev = async (cliArgs) => {
76
79
  let middlewareSourcePath = path.resolve(options['--middleware-source'] || 'src/middleware.js');
77
80
  const publicDir = path.resolve('public')
78
81
 
79
- printBuildOverview({
80
- pagesSourcePath: pagesGeneratedPath,
81
- apiSourcePath,
82
- apiOverviewFiles,
83
- configPath,
84
- pageFiles,
85
- });
82
+ if (pageFiles.length === 0) {
83
+ console.log('\n \x1b[1m@ossy/app\x1b[0m \x1b[2mdev\x1b[0m')
84
+ printBuildOverview({
85
+ pagesSourcePath: pagesGeneratedPath,
86
+ apiSourcePath,
87
+ apiOverviewFiles,
88
+ configPath,
89
+ pageFiles,
90
+ })
91
+ if (resourceTemplatesResult.wrote && resourceTemplatesResult.path) {
92
+ console.log(
93
+ `[@ossy/app][resource-templates] merged ${resourceTemplatesResult.count} template(s) → ${path.relative(process.cwd(), resourceTemplatesResult.path)}`
94
+ )
95
+ }
96
+ }
86
97
 
87
98
  if (!fs.existsSync(middlewareSourcePath)) {
88
99
  middlewareSourcePath = path.resolve(scriptDir, 'middleware.js')
@@ -247,10 +258,43 @@ export const dev = async (cliArgs) => {
247
258
  const pageIds = [
248
259
  ...new Set(pageFiles.map((f) => clientHydrateIdForPage(f, srcDir))),
249
260
  ].sort()
261
+ const overviewSnap = getBuildOverviewSnapshot({
262
+ pagesSourcePath: pagesGeneratedPath,
263
+ apiSourcePath,
264
+ apiOverviewFiles,
265
+ configPath,
266
+ pageFiles,
267
+ })
268
+ const idToPath = Object.fromEntries(
269
+ pageFiles.map((f) => [
270
+ clientHydrateIdForPage(f, srcDir),
271
+ filePathToRoute(f, srcDir).path,
272
+ ])
273
+ )
250
274
  const reporter = pageIds.length
251
- ? createParallelPagesReporter({ pageIds, mode: 'prerender-only' })
275
+ ? createBuildDashboard({
276
+ mode: 'prerender-only',
277
+ pageIds,
278
+ idToPath,
279
+ overview: {
280
+ title: '@ossy/app dev',
281
+ configRel: overviewSnap.configRel,
282
+ apiRoutes: overviewSnap.apiRoutes,
283
+ },
284
+ })
252
285
  : null
253
- reporter?.printSectionTitle('prerender (parallel)')
286
+ reporter?.start()
287
+ if (
288
+ !resourceTemplatesDevLogged &&
289
+ resourceTemplatesResult.wrote &&
290
+ resourceTemplatesResult.path &&
291
+ reporter
292
+ ) {
293
+ reporter.pushLog(
294
+ `[resource-templates] merged ${resourceTemplatesResult.count} → ${path.relative(process.cwd(), resourceTemplatesResult.path)}`
295
+ )
296
+ resourceTemplatesDevLogged = true
297
+ }
254
298
  try {
255
299
  await prerenderReactTask.handler({
256
300
  op: 'prerenderPagesParallel',
@@ -311,7 +355,7 @@ export const dev = async (cliArgs) => {
311
355
  }
312
356
  const norm = filename.replace(/\\/g, '/')
313
357
  if (/\.resource\.js$/.test(norm) && norm.includes('resource-templates/')) {
314
- writeResourceTemplatesBarrelIfPresent({ cwd: process.cwd(), log: true })
358
+ writeResourceTemplatesBarrelIfPresent({ cwd: process.cwd(), log: false })
315
359
  const rtOut = path.join(resourceTemplatesDir(process.cwd()), OSSY_RESOURCE_TEMPLATES_OUT)
316
360
  if (fs.existsSync(rtOut) && typeof watcher?.invalidate === 'function') {
317
361
  watcher.invalidate(rtOut)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/app",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
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.0",
31
- "@ossy/design-system": "^1.11.0",
32
- "@ossy/pages": "^1.11.0",
33
- "@ossy/router": "^1.11.0",
34
- "@ossy/router-react": "^1.11.0",
35
- "@ossy/sdk": "^1.11.0",
36
- "@ossy/sdk-react": "^1.11.0",
37
- "@ossy/themes": "^1.11.0",
30
+ "@ossy/connected-components": "^1.11.1",
31
+ "@ossy/design-system": "^1.11.1",
32
+ "@ossy/pages": "^1.11.1",
33
+ "@ossy/router": "^1.11.1",
34
+ "@ossy/router-react": "^1.11.1",
35
+ "@ossy/sdk": "^1.11.1",
36
+ "@ossy/sdk-react": "^1.11.1",
37
+ "@ossy/themes": "^1.11.1",
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": "a151faf7a9af599b885ea98137575978fa1dffae"
70
+ "gitHead": "dfa200a3ea12c726db2054a0ab902844507716a0"
71
71
  }