@ossy/app 0.15.5 → 0.15.7

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 CHANGED
@@ -23,6 +23,8 @@ export default () => <h1>About</h1>
23
23
 
24
24
  For a single-file setup, use `src/pages.jsx` (legacy).
25
25
 
26
+ Split pages are merged into **`build/.ossy/pages.generated.jsx`** (next to other build output) during `dev` / `build`.
27
+
26
28
  Add `src/config.js` for workspace and theme:
27
29
 
28
30
  ```js
@@ -47,7 +49,7 @@ Define HTTP handlers as an array of `{ id, path, handle(req, res) }` objects (sa
47
49
 
48
50
  **Legacy single file:** `src/api.js` default export is still supported. If it exists, its routes are merged **first**, then every `*.api.js`.
49
51
 
50
- At build/dev time this becomes `.ossy-api.generated.js` (gitignored) whenever you have `src/api.js` and/or any `*.api.js`, so the Rollup entry stays stable when you add or remove split files.
52
+ At build/dev time this becomes **`build/.ossy/api.generated.js`** (under your `--destination` / `build` output, typically gitignored with the rest of `build/`) whenever you have `src/api.js` and/or any `*.api.js`, so the Rollup entry stays stable when you add or remove split files.
51
53
 
52
54
  **Override:** pass `--api-source ./path/to/file.js` to use a single file and skip discovery.
53
55
 
@@ -81,7 +83,7 @@ API routes are matched before the app is rendered. The router supports dynamic s
81
83
 
82
84
  ## Background worker tasks (`*.task.js`)
83
85
 
84
- For long-running job processors (separate from the SSR server), use **`npx @ossy/cli build --worker`** in a package that only needs the worker. It uses the same Rollup + Babel pipeline as `ossy build`, discovers **`*.task.js`** (and `.task.mjs` / `.task.cjs`) under `src/` (or `--pages <dir>`), and writes **`.ossy-tasks.generated.js`** (gitignored) when needed—same idea as `*.api.js` + `.ossy-api.generated.js`.
86
+ For long-running job processors (separate from the SSR server), use **`npx @ossy/cli build --worker`** in a package that only needs the worker. It uses the same Rollup + Babel pipeline as `ossy build`, discovers **`*.task.js`** (and `.task.mjs` / `.task.cjs`) under `src/` (or `--pages <dir>`), and writes **`build/.ossy/tasks.generated.js`** when needed—same idea as `*.api.js` and the generated API bundle.
85
87
 
86
88
  Optional legacy aggregate: **`src/tasks.js`** default export is merged **first**, then each `*.task.js` in path order.
87
89
 
package/cli/build.js CHANGED
@@ -12,7 +12,6 @@ import preserveDirectives from "rollup-plugin-preserve-directives"
12
12
  import json from "@rollup/plugin-json"
13
13
  import copy from 'rollup-plugin-copy';
14
14
  import replace from '@rollup/plugin-replace';
15
- import remove from 'rollup-plugin-delete';
16
15
  import arg from 'arg'
17
16
  import { ensureBuildStubs } from '../scripts/ensure-build-stubs.mjs'
18
17
  import { builtinModules, createRequire } from 'node:module'
@@ -22,6 +21,40 @@ const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
22
21
  const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
23
22
  const TASK_FILE_PATTERN = /\.task\.(mjs|cjs|js)$/
24
23
 
24
+ /** Subfolder under `--destination` / `build` for generated pages/api/task entry stubs. */
25
+ export const OSSY_GEN_DIRNAME = '.ossy'
26
+ export const OSSY_GEN_PAGES_BASENAME = 'pages.generated.jsx'
27
+ export const OSSY_GEN_API_BASENAME = 'api.generated.js'
28
+ export const OSSY_GEN_TASKS_BASENAME = 'tasks.generated.js'
29
+
30
+ export function ossyGeneratedDir (buildPath) {
31
+ return path.join(buildPath, OSSY_GEN_DIRNAME)
32
+ }
33
+
34
+ export function ensureOssyGeneratedDir (buildPath) {
35
+ const dir = ossyGeneratedDir(buildPath)
36
+ fs.mkdirSync(dir, { recursive: true })
37
+ return dir
38
+ }
39
+
40
+ function relToGeneratedImport (generatedAbs, targetAbs) {
41
+ return path.relative(path.dirname(generatedAbs), targetAbs).replace(/\\/g, '/')
42
+ }
43
+
44
+ /** Clears Rollup output dir but keeps `build/.ossy` (generated sources live there). */
45
+ export function ossyCleanBuildDirPlugin (buildPath) {
46
+ return {
47
+ name: 'ossy-clean-build-dir',
48
+ buildStart () {
49
+ if (!fs.existsSync(buildPath)) return
50
+ for (const name of fs.readdirSync(buildPath)) {
51
+ if (name === OSSY_GEN_DIRNAME) continue
52
+ fs.rmSync(path.join(buildPath, name), { recursive: true, force: true })
53
+ }
54
+ },
55
+ }
56
+ }
57
+
25
58
  export function discoverApiFiles(srcDir) {
26
59
  const dir = path.resolve(srcDir)
27
60
  if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
@@ -62,18 +95,18 @@ export function discoverTaskFiles(srcDir) {
62
95
  * Merges `src/api.js` (optional) and every `*.api.js` under the pages tree into one default export array
63
96
  * for the Ossy API router ({ id, path, handle }).
64
97
  */
65
- export function generateApiModule({ cwd, apiFiles, legacyPath }) {
98
+ export function generateApiModule ({ generatedPath, apiFiles, legacyPath }) {
66
99
  const lines = [
67
100
  '// Generated by @ossy/app — do not edit',
68
101
  '',
69
102
  ]
70
103
  const hasLegacy = legacyPath && fs.existsSync(legacyPath)
71
104
  if (hasLegacy) {
72
- const rel = path.relative(cwd, legacyPath).replace(/\\/g, '/')
105
+ const rel = relToGeneratedImport(generatedPath, legacyPath)
73
106
  lines.push(`import _legacyApi from './${rel}'`)
74
107
  }
75
108
  apiFiles.forEach((f, i) => {
76
- const rel = path.relative(cwd, f).replace(/\\/g, '/')
109
+ const rel = relToGeneratedImport(generatedPath, f)
77
110
  lines.push(`import * as _api${i} from './${rel}'`)
78
111
  })
79
112
  lines.push(
@@ -102,11 +135,13 @@ export function generateApiModule({ cwd, apiFiles, legacyPath }) {
102
135
  /**
103
136
  * Resolves the Rollup entry for @ossy/api/source-file and which files to scan for the build overview.
104
137
  */
105
- export function resolveApiSource({ cwd, pagesOpt, scriptDir, explicitApiSource }) {
138
+ export function resolveApiSource ({ cwd, pagesOpt, scriptDir, explicitApiSource, buildPath }) {
106
139
  const srcDir = path.resolve(cwd, pagesOpt)
107
140
  const legacyPath = path.resolve(cwd, 'src/api.js')
108
141
  const defaultStub = path.resolve(scriptDir, 'api.js')
109
- const generatedPath = path.join(cwd, '.ossy-api.generated.js')
142
+ const bp = path.resolve(buildPath ?? path.join(cwd, 'build'))
143
+ ensureOssyGeneratedDir(bp)
144
+ const generatedPath = path.join(ossyGeneratedDir(bp), OSSY_GEN_API_BASENAME)
110
145
 
111
146
  if (explicitApiSource) {
112
147
  const p = path.isAbsolute(explicitApiSource)
@@ -120,13 +155,13 @@ export function resolveApiSource({ cwd, pagesOpt, scriptDir, explicitApiSource }
120
155
 
121
156
  const apiFiles = discoverApiFiles(srcDir)
122
157
  const hasLegacy = fs.existsSync(legacyPath)
123
- // Always feed Rollup the same entry (`.ossy-api.generated.js`) when there is any API surface,
158
+ // Always feed Rollup the same generated entry when there is any API surface,
124
159
  // so adding/removing `*.api.js` does not require changing the replace target mid-dev.
125
160
  if (apiFiles.length > 0 || hasLegacy) {
126
161
  fs.writeFileSync(
127
162
  generatedPath,
128
163
  generateApiModule({
129
- cwd,
164
+ generatedPath,
130
165
  apiFiles,
131
166
  legacyPath: hasLegacy ? legacyPath : null,
132
167
  })
@@ -142,18 +177,18 @@ export function resolveApiSource({ cwd, pagesOpt, scriptDir, explicitApiSource }
142
177
  * Merges `src/tasks.js` (optional) and every `*.task.js` under `src/` into one default export array
143
178
  * of job handlers `{ type, handler }` for the Ossy worker.
144
179
  */
145
- export function generateTaskModule({ cwd, taskFiles, legacyPath }) {
180
+ export function generateTaskModule ({ generatedPath, taskFiles, legacyPath }) {
146
181
  const lines = [
147
182
  '// Generated by @ossy/app — do not edit',
148
183
  '',
149
184
  ]
150
185
  const hasLegacy = legacyPath && fs.existsSync(legacyPath)
151
186
  if (hasLegacy) {
152
- const rel = path.relative(cwd, legacyPath).replace(/\\/g, '/')
187
+ const rel = relToGeneratedImport(generatedPath, legacyPath)
153
188
  lines.push(`import _legacyTasks from './${rel}'`)
154
189
  }
155
190
  taskFiles.forEach((f, i) => {
156
- const rel = path.relative(cwd, f).replace(/\\/g, '/')
191
+ const rel = relToGeneratedImport(generatedPath, f)
157
192
  lines.push(`import * as _task${i} from './${rel}'`)
158
193
  })
159
194
  lines.push(
@@ -182,11 +217,13 @@ export function generateTaskModule({ cwd, taskFiles, legacyPath }) {
182
217
  /**
183
218
  * Resolves the Rollup entry for @ossy/tasks/source-file and which files to list in the worker build overview.
184
219
  */
185
- export function resolveTaskSource({ cwd, pagesOpt, scriptDir, explicitTaskSource }) {
220
+ export function resolveTaskSource ({ cwd, pagesOpt, scriptDir, explicitTaskSource, buildPath }) {
186
221
  const srcDir = path.resolve(cwd, pagesOpt)
187
222
  const legacyPath = path.resolve(cwd, 'src/tasks.js')
188
223
  const defaultStub = path.resolve(scriptDir, 'tasks.js')
189
- const generatedPath = path.join(cwd, '.ossy-tasks.generated.js')
224
+ const bp = path.resolve(buildPath ?? path.join(cwd, 'build'))
225
+ ensureOssyGeneratedDir(bp)
226
+ const generatedPath = path.join(ossyGeneratedDir(bp), OSSY_GEN_TASKS_BASENAME)
190
227
 
191
228
  if (explicitTaskSource) {
192
229
  const p = path.isAbsolute(explicitTaskSource)
@@ -204,7 +241,7 @@ export function resolveTaskSource({ cwd, pagesOpt, scriptDir, explicitTaskSource
204
241
  fs.writeFileSync(
205
242
  generatedPath,
206
243
  generateTaskModule({
207
- cwd,
244
+ generatedPath,
208
245
  taskFiles,
209
246
  legacyPath: hasLegacy ? legacyPath : null,
210
247
  })
@@ -243,12 +280,12 @@ export function filePathToRoute(filePath, srcDir) {
243
280
  return { id, path: routePath }
244
281
  }
245
282
 
246
- export function generatePagesModule(pageFiles, cwd, srcDir = 'src') {
283
+ export function generatePagesModule (pageFiles, cwd, srcDir, generatedPath) {
247
284
  const resolvedSrc = path.resolve(cwd, srcDir)
248
285
  const lines = [
249
286
  "import React from 'react'",
250
287
  ...pageFiles.map((f, i) => {
251
- const rel = path.relative(cwd, f).replace(/\\/g, '/')
288
+ const rel = relToGeneratedImport(generatedPath, f)
252
289
  return `import * as _page${i} from './${rel}'`
253
290
  }),
254
291
  '',
@@ -441,7 +478,7 @@ function isWorkerExternal(id) {
441
478
  }
442
479
 
443
480
  /**
444
- * Worker-only bundle: discovers `*.task.js` (and optional `src/tasks.js`), writes `.ossy-tasks.generated.js`
481
+ * Worker-only bundle: discovers `*.task.js` (and optional `src/tasks.js`), writes `build/.ossy/tasks.generated.js`
445
482
  * when needed, and emits `build/worker.js`. Invoke via `npx @ossy/cli build --worker`.
446
483
  */
447
484
  export async function buildWorker(cliArgs) {
@@ -468,6 +505,7 @@ export async function buildWorker(cliArgs) {
468
505
  pagesOpt,
469
506
  scriptDir,
470
507
  explicitTaskSource: options['--task-source'],
508
+ buildPath,
471
509
  })
472
510
 
473
511
  const workerEntryPath = path.resolve(scriptDir, 'worker-entry.js')
@@ -490,7 +528,7 @@ export async function buildWorker(cliArgs) {
490
528
  input: workerEntryPath,
491
529
  external: isWorkerExternal,
492
530
  plugins: [
493
- remove({ targets: buildPath }),
531
+ ossyCleanBuildDirPlugin(buildPath),
494
532
  replace({
495
533
  preventAssignment: true,
496
534
  delimiters: ['%%', '%%'],
@@ -546,6 +584,8 @@ export const build = async (cliArgs) => {
546
584
  const scriptDir = path.dirname(url.fileURLToPath(import.meta.url))
547
585
  const cwd = process.cwd()
548
586
  const pagesOpt = options['--pages'] || 'src'
587
+ const buildPath = path.resolve(options['--destination'] || 'build')
588
+ ensureOssyGeneratedDir(buildPath)
549
589
  const srcDir = path.resolve(pagesOpt)
550
590
  const configPath = path.resolve(options['--config'] || 'src/config.js');
551
591
  const pageFiles = discoverPageFiles(srcDir)
@@ -556,9 +596,12 @@ export const build = async (cliArgs) => {
556
596
  let effectivePagesSource
557
597
  let isPageFiles = false
558
598
  if (pageFiles.length > 0 || modulePageFiles.length > 0) {
559
- const generatedPath = path.join(cwd, '.ossy-pages.generated.jsx')
560
- fs.writeFileSync(generatedPath, generatePagesModule([...pageFiles, ...modulePageFiles], cwd, pagesOpt))
561
- effectivePagesSource = generatedPath
599
+ const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
600
+ fs.writeFileSync(
601
+ pagesGeneratedPath,
602
+ generatePagesModule([...pageFiles, ...modulePageFiles], cwd, pagesOpt, pagesGeneratedPath)
603
+ )
604
+ effectivePagesSource = pagesGeneratedPath
562
605
  isPageFiles = true
563
606
  } else if (hasPagesJsx) {
564
607
  effectivePagesSource = pagesJsxPath
@@ -574,10 +617,10 @@ export const build = async (cliArgs) => {
574
617
  pagesOpt,
575
618
  scriptDir,
576
619
  explicitApiSource: options['--api-source'],
620
+ buildPath,
577
621
  })
578
622
  let apiSourcePath = resolvedApi
579
623
  let middlewareSourcePath = path.resolve(options['--middleware-source'] || 'src/middleware.js');
580
- const buildPath = path.resolve(options['--destination'] || 'build');
581
624
  const publicDir = path.resolve('public')
582
625
 
583
626
  const inputClient = path.resolve(scriptDir, 'client.js')
@@ -610,7 +653,7 @@ export const build = async (cliArgs) => {
610
653
  const inputOptions = {
611
654
  input: inputFiles,
612
655
  plugins: [
613
- remove({ targets: buildPath }),
656
+ ossyCleanBuildDirPlugin(buildPath),
614
657
  // inject({ 'React': 'react' }),
615
658
  replace({
616
659
  preventAssignment: true,
package/cli/dev.js CHANGED
@@ -7,6 +7,11 @@ import {
7
7
  generatePagesModule,
8
8
  discoverModulePageFiles,
9
9
  resolveApiSource,
10
+ ossyCleanBuildDirPlugin,
11
+ ensureOssyGeneratedDir,
12
+ ossyGeneratedDir,
13
+ OSSY_GEN_PAGES_BASENAME,
14
+ OSSY_GEN_API_BASENAME,
10
15
  } from './build.js';
11
16
  import { watch } from 'rollup';
12
17
  import babel from '@rollup/plugin-babel';
@@ -15,7 +20,6 @@ import resolveCommonJsDependencies from '@rollup/plugin-commonjs'
15
20
  import json from "@rollup/plugin-json"
16
21
  import copy from 'rollup-plugin-copy';
17
22
  import replace from '@rollup/plugin-replace';
18
- import remove from 'rollup-plugin-delete';
19
23
  import arg from 'arg'
20
24
  import { spawn } from 'node:child_process'
21
25
  // import inject from '@rollup/plugin-inject'
@@ -40,6 +44,8 @@ export const dev = async (cliArgs) => {
40
44
  const scriptDir = path.dirname(url.fileURLToPath(import.meta.url))
41
45
  const cwd = process.cwd()
42
46
  const pagesOpt = options['--pages'] || 'src'
47
+ const buildPath = path.resolve(options['--destination'] || 'build')
48
+ ensureOssyGeneratedDir(buildPath)
43
49
  const srcDir = path.resolve(pagesOpt)
44
50
  const configPath = path.resolve(options['--config'] || 'src/config.js');
45
51
  const pageFiles = discoverPageFiles(srcDir)
@@ -50,9 +56,12 @@ export const dev = async (cliArgs) => {
50
56
  let effectivePagesSource
51
57
  let isPageFiles = false
52
58
  if (pageFiles.length > 0 || modulePageFiles.length > 0) {
53
- const generatedPath = path.join(cwd, '.ossy-pages.generated.jsx')
54
- fs.writeFileSync(generatedPath, generatePagesModule([...pageFiles, ...modulePageFiles], cwd, pagesOpt))
55
- effectivePagesSource = generatedPath
59
+ const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
60
+ fs.writeFileSync(
61
+ pagesGeneratedPath,
62
+ generatePagesModule([...pageFiles, ...modulePageFiles], cwd, pagesOpt, pagesGeneratedPath)
63
+ )
64
+ effectivePagesSource = pagesGeneratedPath
56
65
  isPageFiles = true
57
66
  } else if (hasPagesJsx) {
58
67
  effectivePagesSource = pagesJsxPath
@@ -68,10 +77,10 @@ export const dev = async (cliArgs) => {
68
77
  pagesOpt,
69
78
  scriptDir,
70
79
  explicitApiSource: options['--api-source'],
80
+ buildPath,
71
81
  })
72
82
  let apiSourcePath = resolvedApi
73
83
  let middlewareSourcePath = path.resolve(options['--middleware-source'] || 'src/middleware.js');
74
- const buildPath = path.resolve(options['--destination'] || 'build');
75
84
  const publicDir = path.resolve('public')
76
85
 
77
86
  const inputClient = path.resolve(scriptDir, 'client.js')
@@ -103,7 +112,7 @@ export const dev = async (cliArgs) => {
103
112
  const inputOptions = {
104
113
  input: inputFiles,
105
114
  plugins: [
106
- remove({ targets: buildPath }),
115
+ ossyCleanBuildDirPlugin(buildPath),
107
116
  // inject({ 'React': 'react' }),
108
117
  replace({
109
118
  preventAssignment: true,
@@ -230,8 +239,9 @@ export const dev = async (cliArgs) => {
230
239
  pagesOpt,
231
240
  scriptDir,
232
241
  explicitApiSource: undefined,
242
+ buildPath,
233
243
  })
234
- const gen = path.resolve(cwd, '.ossy-api.generated.js')
244
+ const gen = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_API_BASENAME)
235
245
  if (fs.existsSync(gen) && typeof watcher?.invalidate === 'function') {
236
246
  watcher.invalidate(gen)
237
247
  }
@@ -243,8 +253,11 @@ export const dev = async (cliArgs) => {
243
253
  if (!isPageFiles) return
244
254
  const files = discoverPageFiles(srcDir)
245
255
  if (files.length > 0) {
246
- const generatedPath = path.join(cwd, '.ossy-pages.generated.jsx')
247
- fs.writeFileSync(generatedPath, generatePagesModule(files, cwd, pagesOpt))
256
+ const pagesGeneratedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_PAGES_BASENAME)
257
+ fs.writeFileSync(
258
+ pagesGeneratedPath,
259
+ generatePagesModule(files, cwd, pagesOpt, pagesGeneratedPath)
260
+ )
248
261
  }
249
262
  }
250
263
  if (/\.api\.(mjs|cjs|js)$/.test(filename) || /(^|\/)api\.js$/.test(filename.replace(/\\/g, '/'))) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/app",
3
- "version": "0.15.5",
3
+ "version": "0.15.7",
4
4
  "description": "",
5
5
  "source": "./src/index.js",
6
6
  "main": "./src/index.js",
@@ -66,5 +66,5 @@
66
66
  "README.md",
67
67
  "tsconfig.json"
68
68
  ],
69
- "gitHead": "60384d10d4ae86cfe0bbbace31726d600e8febcd"
69
+ "gitHead": "9d5c6036a317fb18db45d65ff6ce237554ffd3af"
70
70
  }