@ossy/app 1.0.9 → 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 CHANGED
@@ -11,7 +11,6 @@ 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
14
 
16
15
  export const PAGE_FILE_PATTERN = /\.page\.(jsx?|tsx?)$/
17
16
  export const API_FILE_PATTERN = /\.api\.(mjs|cjs|js)$/
@@ -56,6 +55,11 @@ export const OSSY_GEN_PAGES_BASENAME = 'pages.generated.jsx'
56
55
  export const OSSY_GEN_API_BASENAME = 'api.generated.js'
57
56
  export const OSSY_GEN_TASKS_BASENAME = 'tasks.generated.js'
58
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
+
59
63
  /** Per-page client entries: `hydrate-<pageId>.jsx` under `.ossy/` */
60
64
  const HYDRATE_STUB_PREFIX = 'hydrate-'
61
65
  const HYDRATE_STUB_SUFFIX = '.jsx'
@@ -143,65 +147,55 @@ export function writeResourceTemplatesBarrelIfPresent ({ cwd = process.cwd(), lo
143
147
  }
144
148
 
145
149
  /**
146
- * Shared Rollup plugins (virtual path replaces, resolve, JSX).
147
- * 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.
148
151
  */
149
- export function createOssyRollupPlugins ({
150
- pagesGeneratedPath,
151
- apiSourcePath,
152
- middlewareSourcePath,
153
- configSourcePath,
154
- nodeEnv,
155
- preferBuiltins = true,
156
- copyPublicFrom,
157
- buildPath,
158
- }) {
159
- const plugins = [
160
- replace({
161
- preventAssignment: true,
162
- delimiters: ['%%', '%%'],
163
- '@ossy/pages/source-file': pagesGeneratedPath,
164
- }),
152
+ export function createOssyAppBundlePlugins ({ nodeEnv }) {
153
+ return [
165
154
  replace({
166
155
  preventAssignment: true,
167
- delimiters: ['%%', '%%'],
168
- '@ossy/api/source-file': apiSourcePath,
156
+ 'process.env.NODE_ENV': JSON.stringify(nodeEnv),
169
157
  }),
170
- replace({
171
- preventAssignment: true,
172
- delimiters: ['%%', '%%'],
173
- '@ossy/middleware/source-file': middlewareSourcePath,
158
+ json(),
159
+ nodeExternals({
160
+ deps: true,
161
+ devDeps: false,
162
+ peerDeps: true,
163
+ packagePath: path.join(process.cwd(), 'package.json'),
174
164
  }),
175
- replace({
176
- preventAssignment: true,
177
- delimiters: ['%%', '%%'],
178
- '@ossy/config/source-file': configSourcePath,
165
+ resolveCommonJsDependencies(),
166
+ resolveDependencies({ preferBuiltins: true }),
167
+ babel({
168
+ babelHelpers: 'bundled',
169
+ extensions: ['.jsx', '.tsx'],
170
+ presets: ['@babel/preset-react'],
179
171
  }),
172
+ ]
173
+ }
174
+
175
+ /**
176
+ * Rollup plugins for browser hydrate bundles.
177
+ */
178
+ export function createOssyClientRollupPlugins ({ nodeEnv, copyPublicFrom, buildPath }) {
179
+ const plugins = [
180
180
  replace({
181
181
  preventAssignment: true,
182
182
  'process.env.NODE_ENV': JSON.stringify(nodeEnv),
183
183
  }),
184
184
  json(),
185
- ]
186
-
187
- plugins.push(
188
185
  nodeExternals({
189
186
  deps: true,
190
187
  devDeps: false,
191
188
  peerDeps: true,
192
189
  packagePath: path.join(process.cwd(), 'package.json'),
193
- })
194
- )
195
-
196
- plugins.push(
190
+ }),
197
191
  resolveCommonJsDependencies(),
198
- resolveDependencies({ preferBuiltins }),
192
+ resolveDependencies({ preferBuiltins: false }),
199
193
  babel({
200
194
  babelHelpers: 'bundled',
201
195
  extensions: ['.jsx', '.tsx'],
202
196
  presets: ['@babel/preset-react'],
203
- })
204
- )
197
+ }),
198
+ ]
205
199
  if (copyPublicFrom && fs.existsSync(copyPublicFrom)) {
206
200
  plugins.push(
207
201
  copy({
@@ -212,6 +206,39 @@ export function createOssyRollupPlugins ({
212
206
  return plugins
213
207
  }
214
208
 
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))
235
+ }
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'))
240
+ }
241
+
215
242
  /**
216
243
  * Recursively lists files under `srcDir` whose basename matches `filePattern` (e.g. `/\.api\.js$/`).
217
244
  */
@@ -320,26 +347,20 @@ export function generateTaskModule ({ generatedPath, taskFiles }) {
320
347
  }
321
348
 
322
349
  /**
323
- * Resolves the Rollup entry for @ossy/tasks/source-file and which files to list in the worker build overview.
350
+ * Writes `build/.ossy/tasks.generated.js` and returns its path (stable Rollup input; empty when no task files).
324
351
  */
325
- export function resolveTaskSource ({ srcDir, scriptDir, buildPath }) {
326
- const defaultStub = path.resolve(scriptDir, 'tasks.js')
352
+ export function resolveTaskSource ({ srcDir, buildPath }) {
327
353
  ensureOssyGeneratedDir(buildPath)
328
354
  const generatedPath = path.join(ossyGeneratedDir(buildPath), OSSY_GEN_TASKS_BASENAME)
329
-
330
355
  const taskFiles = discoverFilesByPattern(srcDir, TASK_FILE_PATTERN)
331
- if (taskFiles.length > 0) {
332
- fs.writeFileSync(
356
+ fs.writeFileSync(
357
+ generatedPath,
358
+ generateTaskModule({
333
359
  generatedPath,
334
- generateTaskModule({
335
- generatedPath,
336
- taskFiles,
337
- })
338
- )
339
- return { taskSourcePath: generatedPath, taskOverviewFiles: taskFiles, usedGenerated: true }
340
- }
341
-
342
- return { taskSourcePath: defaultStub, taskOverviewFiles: [], usedGenerated: false }
360
+ taskFiles,
361
+ })
362
+ )
363
+ return { taskSourcePath: generatedPath, taskOverviewFiles: taskFiles }
343
364
  }
344
365
 
345
366
  export function filePathToRoute(filePath, srcDir) {
@@ -600,8 +621,6 @@ export const build = async (cliArgs) => {
600
621
  let middlewareSourcePath = path.resolve('src/middleware.js');
601
622
  const publicDir = path.resolve('public')
602
623
 
603
- const inputServer = path.resolve(scriptDir, 'server.js')
604
-
605
624
  printBuildOverview({
606
625
  pagesSourcePath: pagesGeneratedPath,
607
626
  apiSourcePath,
@@ -618,40 +637,38 @@ export const build = async (cliArgs) => {
618
637
  ? configPath
619
638
  : path.resolve(scriptDir, 'default-config.js')
620
639
 
621
- const sharedPluginOpts = {
622
- pagesGeneratedPath,
623
- apiSourcePath,
624
- middlewareSourcePath,
625
- configSourcePath,
626
- nodeEnv: 'production',
627
- buildPath,
628
- }
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)
629
643
 
630
- const serverPlugins = createOssyRollupPlugins({
631
- ...sharedPluginOpts,
632
- preferBuiltins: true,
633
- copyPublicFrom: publicDir,
644
+ await bundleOssyNodeEntry({
645
+ inputPath: pagesGeneratedPath,
646
+ outputFile: pagesBundlePath,
647
+ nodeEnv: 'production',
634
648
  })
635
-
636
- const serverBundle = await rollup({
637
- input: { server: inputServer },
638
- plugins: serverPlugins,
649
+ await bundleOssyNodeEntry({
650
+ inputPath: apiSourcePath,
651
+ outputFile: apiBundlePath,
652
+ nodeEnv: 'production',
639
653
  })
640
- await serverBundle.write({
641
- dir: buildPath,
642
- format: 'esm',
643
- preserveModules: true,
644
- preserveModulesRoot: path.dirname(inputServer),
645
- entryFileNames ({ name }) {
646
- return name === 'server' ? 'server.js' : '[name].js'
647
- },
648
- assetFileNames: '[name][extname]',
654
+ const { taskSourcePath } = resolveTaskSource({ srcDir, buildPath })
655
+ await bundleOssyNodeEntry({
656
+ inputPath: taskSourcePath,
657
+ outputFile: tasksBundlePath,
658
+ nodeEnv: 'production',
649
659
  })
650
- await serverBundle.close()
651
660
 
652
- const clientPlugins = createOssyRollupPlugins({
653
- ...sharedPluginOpts,
654
- preferBuiltins: false,
661
+ copyOssyAppRuntime({
662
+ scriptDir,
663
+ buildPath,
664
+ middlewareSourcePath,
665
+ configSourcePath,
666
+ })
667
+
668
+ const clientPlugins = createOssyClientRollupPlugins({
669
+ nodeEnv: 'production',
670
+ copyPublicFrom: publicDir,
671
+ buildPath,
655
672
  })
656
673
 
657
674
  if (Object.keys(clientHydrateInput).length > 0) {
@@ -675,7 +692,5 @@ export const build = async (cliArgs) => {
675
692
  await clientBundle.close()
676
693
  }
677
694
 
678
- ensureBuildStubs(buildPath)
679
-
680
695
  console.log('[@ossy/app][build] Finished');
681
696
  };
package/cli/dev.js CHANGED
@@ -7,14 +7,22 @@ import {
7
7
  PAGE_FILE_PATTERN,
8
8
  generatePagesModule,
9
9
  resolveApiSource,
10
+ resolveTaskSource,
10
11
  resetOssyBuildDir,
11
- createOssyRollupPlugins,
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,
@@ -48,7 +56,6 @@ export const dev = async (cliArgs) => {
48
56
  pagesGeneratedPath,
49
57
  generatePagesModule(pageFiles, srcDir, pagesGeneratedPath)
50
58
  )
51
- const effectivePagesSource = pagesGeneratedPath
52
59
  const ossyDir = ossyGeneratedDir(buildPath)
53
60
  writePageHydrateStubs(pageFiles, srcDir, ossyDir)
54
61
  const clientHydrateInput = buildClientHydrateInput(pageFiles, srcDir, ossyDir)
@@ -61,13 +68,12 @@ export const dev = async (cliArgs) => {
61
68
  buildPath,
62
69
  })
63
70
  let apiSourcePath = resolvedApi
71
+ resolveTaskSource({ srcDir, buildPath })
64
72
  let middlewareSourcePath = path.resolve(options['--middleware-source'] || 'src/middleware.js');
65
73
  const publicDir = path.resolve('public')
66
74
 
67
- const inputServer = path.resolve(scriptDir, 'server.js')
68
-
69
75
  printBuildOverview({
70
- pagesSourcePath: effectivePagesSource,
76
+ pagesSourcePath: pagesGeneratedPath,
71
77
  apiSourcePath,
72
78
  apiOverviewFiles,
73
79
  configPath,
@@ -82,37 +88,43 @@ export const dev = async (cliArgs) => {
82
88
  ? configPath
83
89
  : path.resolve(scriptDir, 'default-config.js')
84
90
 
85
- const sharedPluginOpts = {
86
- pagesGeneratedPath: effectivePagesSource,
87
- apiSourcePath,
88
- middlewareSourcePath,
89
- configSourcePath,
90
- nodeEnv: 'development',
91
- buildPath,
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
+ })
92
118
  }
93
119
 
94
- const serverPlugins = createOssyRollupPlugins({
95
- ...sharedPluginOpts,
96
- preferBuiltins: true,
97
- copyPublicFrom: publicDir,
98
- })
120
+ await runNodeBundles()
99
121
 
100
- const clientPlugins = createOssyRollupPlugins({
101
- ...sharedPluginOpts,
102
- preferBuiltins: false,
122
+ const clientPlugins = createOssyClientRollupPlugins({
123
+ nodeEnv: 'development',
124
+ copyPublicFrom: publicDir,
125
+ buildPath,
103
126
  })
104
127
 
105
- const serverOutput = {
106
- dir: buildPath,
107
- format: 'esm',
108
- preserveModules: true,
109
- preserveModulesRoot: path.dirname(inputServer),
110
- entryFileNames ({ name }) {
111
- return name === 'server' ? 'server.js' : '[name].js'
112
- },
113
- assetFileNames: '[name][extname]',
114
- }
115
-
116
128
  const clientOutput = {
117
129
  dir: buildPath,
118
130
  format: 'esm',
@@ -167,12 +179,37 @@ export const dev = async (cliArgs) => {
167
179
  }
168
180
  }
169
181
 
182
+ const nodeWatchOpts = { watch: { clearScreen: false } }
170
183
  const watchConfigs = [
171
184
  {
172
- input: { server: inputServer },
173
- output: serverOutput,
174
- plugins: serverPlugins,
175
- watch: { clearScreen: false },
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,
176
213
  },
177
214
  ]
178
215
  if (Object.keys(clientHydrateInput).length > 0) {
@@ -196,11 +233,17 @@ export const dev = async (cliArgs) => {
196
233
  console.log(`[@ossy/app][dev] Built in ${event.duration}ms`)
197
234
  }
198
235
  if (event.code === 'END') {
236
+ copyOssyAppRuntime({
237
+ scriptDir,
238
+ buildPath,
239
+ middlewareSourcePath,
240
+ configSourcePath,
241
+ })
199
242
  scheduleRestart()
200
243
  }
201
244
  })
202
245
 
203
- const regenApiBundle = () => {
246
+ const regenApiGenerated = () => {
204
247
  if (options['--api-source']) return
205
248
  resolveApiSource({
206
249
  srcDir,
@@ -212,6 +255,13 @@ export const dev = async (cliArgs) => {
212
255
  }
213
256
  }
214
257
 
258
+ const regenTasksGenerated = () => {
259
+ resolveTaskSource({ srcDir, buildPath })
260
+ if (fs.existsSync(tasksGeneratedPath) && typeof watcher?.invalidate === 'function') {
261
+ watcher.invalidate(tasksGeneratedPath)
262
+ }
263
+ }
264
+
215
265
  fs.watch(srcDir, { recursive: true }, (eventType, filename) => {
216
266
  if (!filename) return
217
267
  if (/\.page\.(jsx?|tsx?)$/.test(filename)) {
@@ -228,7 +278,10 @@ export const dev = async (cliArgs) => {
228
278
  }
229
279
  }
230
280
  if (/\.api\.(mjs|cjs|js)$/.test(filename)) {
231
- regenApiBundle()
281
+ regenApiGenerated()
282
+ }
283
+ if (/\.task\.(mjs|cjs|js)$/.test(filename)) {
284
+ regenTasksGenerated()
232
285
  }
233
286
  const norm = filename.replace(/\\/g, '/')
234
287
  if (/\.resource\.js$/.test(norm) && norm.includes('resource-templates/')) {
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 '%%@ossy/pages/source-file%%'
12
- import ApiRoutes from '%%@ossy/api/source-file%%'
13
- import Middleware from '%%@ossy/middleware/source-file%%'
14
- import configModule from '%%@ossy/config/source-file%%'
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
- /** `api.generated.js` is always present; default may still be empty. */
18
+ /** API bundle default may be an empty array. */
19
19
  const apiRouteList = ApiRoutes ?? []
20
20
  const pageList = pages ?? []
21
21
 
@@ -1,5 +1,5 @@
1
1
  import 'dotenv/config'
2
- import taskHandlers from '%%@ossy/tasks/source-file%%'
2
+ import taskHandlers from './.ossy/tasks.bundle.js'
3
3
  import { runWorkerScheduler } from './worker-runtime.js'
4
4
 
5
5
  runWorkerScheduler(taskHandlers)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/app",
3
- "version": "1.0.9",
3
+ "version": "1.1.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.0.9",
31
- "@ossy/design-system": "^1.0.9",
32
- "@ossy/pages": "^1.0.9",
33
- "@ossy/router": "^1.0.9",
34
- "@ossy/router-react": "^1.0.9",
35
- "@ossy/sdk": "^1.0.9",
36
- "@ossy/sdk-react": "^1.0.9",
37
- "@ossy/themes": "^1.0.9",
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",
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": "c9da4864730c693fe18339f0920a0802ce9c8ebf"
70
+ "gitHead": "5977a77f97776131077a848081098ab6ec4cf837"
71
71
  }