@webqit/webflo 0.20.4-next.2 → 0.20.4-next.3

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.
Files changed (43) hide show
  1. package/package.json +5 -20
  2. package/site/docs/concepts/realtime.md +45 -44
  3. package/site/docs/getting-started.md +40 -40
  4. package/src/{Context.js → CLIContext.js} +9 -8
  5. package/src/build-pi/esbuild-plugin-livejs-transform.js +35 -0
  6. package/src/{runtime-pi/webflo-client/webflo-codegen.js → build-pi/index.js} +145 -141
  7. package/src/index.js +3 -1
  8. package/src/init-pi/index.js +6 -3
  9. package/src/init-pi/templates/pwa/package.json +2 -2
  10. package/src/init-pi/templates/web/package.json +2 -2
  11. package/src/runtime-pi/AppBootstrap.js +38 -0
  12. package/src/runtime-pi/WebfloRuntime.js +50 -47
  13. package/src/runtime-pi/apis.js +9 -0
  14. package/src/runtime-pi/index.js +2 -4
  15. package/src/runtime-pi/webflo-client/WebfloClient.js +31 -35
  16. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +16 -14
  17. package/src/runtime-pi/webflo-client/WebfloSubClient.js +13 -13
  18. package/src/runtime-pi/webflo-client/bootstrap.js +37 -0
  19. package/src/runtime-pi/webflo-client/index.js +2 -8
  20. package/src/runtime-pi/webflo-client/webflo-devmode.js +3 -3
  21. package/src/runtime-pi/webflo-fetch/LiveResponse.js +127 -96
  22. package/src/runtime-pi/webflo-fetch/index.js +435 -5
  23. package/src/runtime-pi/webflo-routing/HttpCookies.js +1 -1
  24. package/src/runtime-pi/webflo-routing/HttpEvent.js +5 -6
  25. package/src/runtime-pi/webflo-routing/HttpUser.js +7 -7
  26. package/src/runtime-pi/webflo-server/ServerSideCookies.js +3 -1
  27. package/src/runtime-pi/webflo-server/ServerSideSession.js +2 -1
  28. package/src/runtime-pi/webflo-server/WebfloServer.js +98 -195
  29. package/src/runtime-pi/webflo-server/bootstrap.js +59 -0
  30. package/src/runtime-pi/webflo-server/index.js +2 -6
  31. package/src/runtime-pi/webflo-server/webflo-devmode.js +13 -24
  32. package/src/runtime-pi/webflo-worker/WebfloWorker.js +11 -15
  33. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +2 -1
  34. package/src/runtime-pi/webflo-worker/bootstrap.js +38 -0
  35. package/src/runtime-pi/webflo-worker/index.js +3 -7
  36. package/src/webflo-cli.js +1 -2
  37. package/src/runtime-pi/webflo-fetch/cookies.js +0 -10
  38. package/src/runtime-pi/webflo-fetch/fetch.js +0 -16
  39. package/src/runtime-pi/webflo-fetch/formdata.js +0 -54
  40. package/src/runtime-pi/webflo-fetch/headers.js +0 -151
  41. package/src/runtime-pi/webflo-fetch/message.js +0 -49
  42. package/src/runtime-pi/webflo-fetch/request.js +0 -62
  43. package/src/runtime-pi/webflo-fetch/response.js +0 -110
@@ -1,21 +1,18 @@
1
1
  import Fs from 'fs';
2
2
  import Path from 'path';
3
+ import Url from 'url';
3
4
  import Jsdom from 'jsdom';
4
5
  import EsBuild from 'esbuild';
5
6
  import { gzipSync, brotliCompressSync } from 'zlib';
6
7
  import { _afterLast, _beforeLast } from '@webqit/util/str/index.js';
7
8
  import { _isObject, _isArray } from '@webqit/util/js/index.js';
8
9
  import { jsFile } from '@webqit/backpack/src/dotfile/index.js';
9
- import { Context } from '../../Context.js';
10
- import {
11
- readClientConfig,
12
- readWorkerConfig,
13
- readLayoutConfig,
14
- readEnvConfig,
15
- scanRoots,
16
- scanRouteHandlers,
17
- } from '../../deployment-pi/util.js';
18
- import '../webflo-url/urlpattern.js';
10
+ import { bootstrap as serverBootstrap } from '../runtime-pi/webflo-server/bootstrap.js';
11
+ import { bootstrap as clientBootstrap } from '../runtime-pi/webflo-client/bootstrap.js';
12
+ import { bootstrap as workerBootstrap } from '../runtime-pi/webflo-worker/bootstrap.js';
13
+ import { LiveJSTransform } from './esbuild-plugin-livejs-transform.js';
14
+ import { CLIContext } from '../CLIContext.js';
15
+ import '../runtime-pi/webflo-url/urlpattern.js';
19
16
 
20
17
  function declareConfig({ $source, configExport, indentation = 0 }) {
21
18
  const varName = 'config';
@@ -51,20 +48,25 @@ function declareConfig({ $source, configExport, indentation = 0 }) {
51
48
  }
52
49
  }
53
50
 
54
- function declareRoutes({ $context, $config, $source, which, offset, roots = [] }) {
51
+ function declareRoutes({ $context, $source, bootstrap }) {
55
52
  const { flags: FLAGS, logger: LOGGER } = $context;
56
53
  LOGGER?.log(LOGGER.style.keyword(`> `) + `Declaring routes...`);
54
+
57
55
  // Define vars
58
56
  const varName = 'routes';
59
- const targetDir = Path.join(FLAGS.outdir || $config.LAYOUT.PUBLIC_DIR, offset);
57
+ const targetDir = FLAGS.outdir || bootstrap.outdir;
58
+
60
59
  // >> Routes mapping
61
60
  $source.code.push(`const ${varName} = {};`);
61
+
62
62
  // Route entries
63
63
  let routeCount = 0;
64
- scanRouteHandlers($config.LAYOUT, which, (file, route, filename, fstat) => {
64
+ for (const route of Object.keys(bootstrap.routes)) {
65
+ const file = bootstrap.routes[route];
66
+ const fstat = Fs.statSync(file);
65
67
  // The "import" code
66
68
  const routeId = 'route' + (++routeCount);
67
- const importPath = Path.relative(targetDir, file);
69
+ const importPath = file;
68
70
  $source.imports[importPath] = '* as ' + routeId;
69
71
  // The route def
70
72
  $source.code.push(`${varName}['${route}'] = ${routeId};`);
@@ -72,35 +74,52 @@ function declareRoutes({ $context, $config, $source, which, offset, roots = [] }
72
74
  LOGGER?.log(
73
75
  LOGGER.style.comment(` [${route}]: `) + LOGGER.style.url(importPath) + LOGGER.style.comment(` (${fstat.size / 1024} KB)`)
74
76
  );
75
- }, offset, roots);
76
- // >> Specials
77
- $source.code.push(`Object.defineProperty(${varName}, '$root', { value: '${offset}' });`);
78
- $source.code.push(`Object.defineProperty(${varName}, '$sparoots', { value: ${JSON.stringify(roots)} });`);
77
+ }
78
+
79
79
  if (!routeCount) {
80
80
  LOGGER?.log(LOGGER.style.comment(` (none)`));
81
81
  }
82
82
  }
83
83
 
84
84
  function writeImportWebflo($source, which) {
85
- $source.imports[`@webqit/webflo/src/runtime-pi/webflo-${which}/index.js`] = `{ start }`;
85
+ const importUrl = Url.fileURLToPath(import.meta.url);
86
+ const importPath = Path.join(Path.dirname(importUrl), `../runtime-pi/webflo-${which}/index.js`);
87
+ $source.imports[importPath] = `{ start }`;
86
88
  }
87
89
 
88
- function writeScriptBody({ $context, $config, $source, which, offset, roots, configExport }) {
90
+ function writeScriptBody({ $context, $source, bootstrap, configExport, which }) {
91
+ // >> Init
92
+ if (bootstrap.$init) {
93
+ const importPath = bootstrap.$init;
94
+ $source.imports[importPath] = `* as init`;
95
+ } else {
96
+ $source.code.push(`const init = null;`);
97
+ }
98
+
89
99
  // >> Config
90
100
  $source.code.push(`// >> Config export`);
91
101
  declareConfig({ $source, configExport });
92
102
  $source.code.push(``);
103
+
93
104
  // >> Routes mapping
94
105
  $source.code.push(`// >> Routes`);
95
- declareRoutes({ $context, $config, $source, which, offset, roots });
106
+ declareRoutes({ $context, $source, bootstrap, which });
107
+ $source.code.push(``);
108
+
109
+ // >> Specials
110
+ $source.code.push(`// >> Routes`);
111
+ $source.code.push(`const $root = '${bootstrap.offset || null}';`);
112
+ $source.code.push(`const $roots = ${bootstrap.$roots?.length ? JSON.stringify(bootstrap.$roots) : '[]'};`);
113
+ $source.code.push(`const $sparoots = ${bootstrap.$sparoots?.length ? JSON.stringify(bootstrap.$sparoots) : '[]'};`);
96
114
  $source.code.push(``);
115
+
97
116
  // >> Startup
98
117
  $source.code.push(`// >> Startup`);
99
- $source.code.push(`self.webqit = self.webqit || {};`);
100
- $source.code.push(`self.webqit.app = await start.call({ config, routes })`);
118
+ $source.code.push(`globalThis.webqit = globalThis.webqit || {};`);
119
+ $source.code.push(`globalThis.webqit.app = await start({ init, config, routes, $root, $roots, $sparoots });`);
101
120
  }
102
121
 
103
- async function bundleScript({ $context, $source, which, outfile, asModule = false, ...restParams }) {
122
+ async function bundleScript({ $context, $source, which, outfile, asModule = true, ...restParams }) {
104
123
  const { flags: FLAGS, logger: LOGGER } = $context;
105
124
  // >> Show banner...
106
125
  LOGGER?.log(LOGGER.style.keyword(`---`));
@@ -126,11 +145,14 @@ async function bundleScript({ $context, $source, which, outfile, asModule = fals
126
145
  const bundlingConfig = {
127
146
  entryPoints: [moduleFile],
128
147
  outfile,
129
- bundle: true,
148
+ bundle: which === 'server' ? false : true,
130
149
  minify: true,
150
+ format: asModule ? 'esm' : 'iife',
151
+ platform: which === 'server' ? 'node' : 'browser', // optional but good for clarity
152
+ treeShaking: true, // Important optimization
131
153
  banner: { js: '/** @webqit/webflo */', },
132
154
  footer: { js: '', },
133
- format: 'esm',
155
+ plugins: [ LiveJSTransform() ],
134
156
  ...(restParams.buildParams || {})
135
157
  };
136
158
  if (!asModule) {
@@ -248,38 +270,35 @@ function handleEmbeds($context, embeds, targetDocumentFile) {
248
270
 
249
271
  // -------------
250
272
 
251
- async function generateClientScript({ $context, $config, offset = '', roots = [], ...restParams }) {
273
+ async function generateClientScript({ $context, bootstrap, ...restParams }) {
252
274
  const { flags: FLAGS, logger: LOGGER } = $context;
253
- // -----------
254
- const inSplitMode = !!roots.length || !!offset;
255
- const targetDocumentFile = Path.join($config.LAYOUT.PUBLIC_DIR, offset, 'index.html');
256
- // For when we're in split mode
257
- const outfile_theWebfloClient = $config.CLIENT.filename.replace(/\.js$/, '.webflo.js');
258
- const outfile_theWebfloClientPublic = Path.join($config.CLIENT.public_base_url, outfile_theWebfloClient);
259
- // For when we're monolith mode
260
- const outfile_mainBuild = Path.join(offset, $config.CLIENT.filename);
261
- let publicBaseUrl = $config.CLIENT.public_base_url;
262
- if (FLAGS.outdir) {
263
- publicBaseUrl = '/' + Path.relative($config.LAYOUT.PUBLIC_DIR, FLAGS.outdir);
264
- }
265
- const outfile_mainBuildPublic = Path.join(publicBaseUrl, outfile_mainBuild);
266
- // The source code
275
+
276
+ const inSplitMode = !!bootstrap.$roots.length || !!bootstrap.offset;
277
+
278
+ const targetDocumentFile = Path.join(FLAGS.outdir || bootstrap.outdir, 'index.html');
279
+ const publicBaseUrl = bootstrap.config.CLIENT.public_base_url;
280
+
281
+ const sharedBuild_filename = bootstrap.config.CLIENT.filename.replace(/\.js$/, '.webflo.js');
282
+ const outfile_sharedBuild = Path.join(bootstrap.config.LAYOUT.PUBLIC_DIR, sharedBuild_filename);
283
+ const outfile_sharedBuildPublic = Path.join(publicBaseUrl, sharedBuild_filename);
284
+
285
+ const outfile_clientBuild = Path.join(FLAGS.outdir || bootstrap.outdir, bootstrap.config.CLIENT.filename);
286
+ const outfile_clientBuildPublic = Path.join(publicBaseUrl, Path.relative(bootstrap.config.LAYOUT.PUBLIC_DIR, outfile_clientBuild));
287
+
267
288
  const $source = { imports: {}, code: [] };
268
289
  const embeds = { all: [], current: [] };
269
- // -----------
270
- // 1. Derive params
271
- const configExport = structuredClone({ CLIENT: $config.CLIENT, ENV: $config.ENV });
272
- if ($config.CLIENT.capabilities?.service_worker === true) {
273
- configExport.CLIENT.capabilities.service_worker = {
274
- filename: Path.join(publicBaseUrl.replace(/^\//, ''), $config.WORKER.filename),
275
- scope: $config.WORKER.scope
290
+
291
+ const configExport = structuredClone({ ENV: bootstrap.config.ENV, CLIENT: bootstrap.config.CLIENT, WORKER: {} });
292
+ if (bootstrap.config.CLIENT.capabilities?.service_worker === true) {
293
+ configExport.WORKER = {
294
+ filename: Path.join(publicBaseUrl.replace(/^\//, ''), bootstrap.config.WORKER.filename),
295
+ scope: bootstrap.config.WORKER.scope
276
296
  };
277
297
  }
278
- // 2. Add the Webflo Runtime
298
+
279
299
  const outfiles = [];
280
300
  if (inSplitMode) {
281
- if (!offset) {
282
- // We're building the Webflo client as a standalone script
301
+ if (!bootstrap.offset) {
283
302
  LOGGER?.log(LOGGER.style.keyword(`---`));
284
303
  LOGGER?.log(`[SPLIT_MODE] Base Build`);
285
304
  LOGGER?.log(LOGGER.style.keyword(`---`));
@@ -290,79 +309,64 @@ async function generateClientScript({ $context, $config, offset = '', roots = []
290
309
  $context,
291
310
  $source: $$source,
292
311
  which: 'client',
293
- outfile: Path.join($config.LAYOUT.PUBLIC_DIR, outfile_theWebfloClient),
312
+ outfile: outfile_sharedBuild,
294
313
  asModule: true
295
314
  });
296
315
  outfiles.push(..._outfiles);
297
316
  }
298
317
  if (FLAGS['auto-embed']) {
299
- embeds.current.push(outfile_theWebfloClientPublic);
300
- embeds.current.push(outfile_mainBuildPublic);
318
+ embeds.current.push(outfile_sharedBuildPublic);
319
+ embeds.current.push(outfile_clientBuildPublic);
301
320
  }
302
321
  } else {
303
- // We're building the Webflo client as part of the main script
304
322
  writeImportWebflo($source, 'client');
305
323
  if (FLAGS['auto-embed']) {
306
- embeds.current.push(outfile_mainBuildPublic);
324
+ embeds.current.push(outfile_clientBuildPublic);
307
325
  }
308
326
  }
309
- // 3. Write the body and bundle
327
+
310
328
  writeScriptBody({
311
329
  $context,
312
- $config,
313
330
  $source,
314
- which: 'client',
315
- offset,
316
- roots,
331
+ bootstrap,
317
332
  configExport,
333
+ which: 'client',
318
334
  ...restParams
319
335
  });
320
- // 4. Bundle
336
+
321
337
  const _outfiles = await bundleScript({
322
338
  $context,
323
339
  $source,
324
340
  which: 'client',
325
- outfile: Path.join(FLAGS.outdir || $config.LAYOUT.PUBLIC_DIR, outfile_mainBuild),
341
+ outfile: outfile_clientBuild,
326
342
  asModule: true,
327
343
  ...restParams
328
344
  });
329
345
  outfiles.push(..._outfiles);
330
- // 4. Embed/unembed
331
- embeds.all.push(outfile_theWebfloClientPublic);
332
- embeds.all.push(outfile_mainBuildPublic);
346
+
347
+ embeds.all.push(outfile_sharedBuildPublic);
348
+ embeds.all.push(outfile_clientBuildPublic);
333
349
  handleEmbeds($context, embeds, targetDocumentFile);
334
- // -----------
335
- if (FLAGS.recursive && roots.length) {
336
- const $roots = roots.slice(0);
337
- const _outfiles = await generateClientScript({
338
- $context,
339
- $config,
340
- offset: $roots.shift(),
341
- roots: $roots,
342
- ...restParams
343
- });
344
- return outfiles.concat(_outfiles);
345
- }
350
+
346
351
  return outfiles;
347
352
  }
348
353
 
349
- async function generateWorkerScript({ $context, $config, offset = '', roots = [], ...restParams }) {
354
+ async function generateWorkerScript({ $context, bootstrap, ...restParams }) {
350
355
  const { flags: FLAGS } = $context;
351
- // -----------
352
- const outfile_mainBuild = Path.join(offset, $config.WORKER.filename);
356
+
353
357
  const $source = { imports: {}, code: [] };
354
- // -----------
355
- // 1. Derive params
356
- const configExport = structuredClone({ WORKER: $config.WORKER, ENV: $config.ENV });
357
- if ($config.CLIENT.capabilities?.webpush === true) {
358
- configExport.WORKER.capabilities = {
358
+
359
+ const outfile_workerBuild = Path.join(FLAGS.outdir || bootstrap.outdir, bootstrap.config.WORKER.filename);
360
+
361
+ const configExport = structuredClone({ ENV: bootstrap.config.ENV, CLIENT: { capabilities: {} }, WORKER: bootstrap.config.WORKER });
362
+ if (bootstrap.config.CLIENT.capabilities?.webpush === true) {
363
+ configExport.CLIENT.capabilities = {
359
364
  webpush: true
360
365
  };
361
366
  }
362
- // Fetching strategies
367
+
363
368
  for (const strategy of ['cache_first_urls', 'cache_only_urls']) {
364
369
  if (configExport.WORKER[strategy].length) {
365
- // Separate URLs from patterns
366
370
  const [urls, patterns] = configExport.WORKER[strategy].reduce(([urls, patterns], url) => {
367
371
  const patternInstance = new URLPattern(url, 'http://localhost');
368
372
  const isPattern = patternInstance.isPattern();
@@ -371,20 +375,17 @@ async function generateWorkerScript({ $context, $config, offset = '', roots = []
371
375
  }
372
376
  return isPattern ? [urls, patterns.concat(patternInstance)] : [urls.concat(url), patterns];
373
377
  }, [[], []]);
374
- // Resolve patterns
375
378
  if (patterns.length) {
376
- // List all files
377
379
  function scanDir(dir) {
378
380
  Fs.readdirSync(dir).reduce((result, f) => {
379
381
  const resource = Path.join(dir, f);
380
382
  if (f.startsWith('.')) return result;
381
383
  return result.concat(
382
- Fs.statSync(resource).isDirectory() ? scanDir(resource) : '/' + Path.relative($config.LAYOUT.PUBLIC_DIR, resource)
384
+ Fs.statSync(resource).isDirectory() ? scanDir(resource) : '/' + Path.relative(bootstrap.config.LAYOUT.PUBLIC_DIR, resource)
383
385
  );
384
386
  }, []);
385
387
  }
386
- const files = scanDir($config.LAYOUT.PUBLIC_DIR);
387
- // Resolve patterns from files
388
+ const files = scanDir(bootstrap.config.LAYOUT.PUBLIC_DIR);
388
389
  configExport.WORKER[strategy] = patterns.reduce((all, pattern) => {
389
390
  const matchedFiles = files.filter((file) => pattern.test(file, 'http://localhost'));
390
391
  if (matchedFiles.length) return all.concat(matchedFiles);
@@ -393,77 +394,80 @@ async function generateWorkerScript({ $context, $config, offset = '', roots = []
393
394
  }
394
395
  }
395
396
  }
396
- // 2. Add the Webflo Runtime
397
+
397
398
  writeImportWebflo($source, 'worker');
398
- // 3. Write the body and bundle
399
399
  writeScriptBody({
400
400
  $context,
401
- $config,
402
401
  $source,
403
- which: 'worker',
404
- offset,
405
- roots,
402
+ bootstrap,
406
403
  configExport,
404
+ which: 'worker',
407
405
  ...restParams
408
406
  });
409
- // 4. Bundle
410
- const outfiles = await bundleScript({
407
+
408
+ return await bundleScript({
411
409
  $context,
412
410
  $source,
413
411
  which: 'worker',
414
- outfile: Path.join(FLAGS.outdir || $config.LAYOUT.PUBLIC_DIR, outfile_mainBuild),
415
- asModule: false,
412
+ outfile: outfile_workerBuild,
413
+ asModule: true,
414
+ ...restParams
415
+ });
416
+ }
417
+
418
+ async function generateServerScript({ $context, bootstrap, ...restParams }) {
419
+ const $source = { imports: {}, code: [] };
420
+ const outfile_serverBuild = Path.join(bootstrap.outdir, 'app.js'); // Must not consult FLAGS.outdir
421
+
422
+ writeImportWebflo($source, 'server');
423
+ writeScriptBody({
424
+ $context,
425
+ $source,
426
+ bootstrap,
427
+ configExport: bootstrap.config,
428
+ which: 'server',
429
+ ...restParams
430
+ });
431
+
432
+ return await bundleScript({
433
+ $context,
434
+ $source,
435
+ which: 'server',
436
+ outfile: outfile_serverBuild,
437
+ asModule: true,
416
438
  ...restParams
417
439
  });
418
- // -----------
419
- if (FLAGS.recursive && roots.length) {
420
- const $roots = roots.slice(0);
421
- const _outfiles = await generateWorkerScript({
422
- $context,
423
- $config,
424
- offset: $roots.shift(),
425
- roots: $roots,
426
- ...restParams
427
- });
428
- return outfiles.concat(_outfiles);
429
- }
430
- return outfiles;
431
440
  }
432
441
 
433
- export async function generate({ client = true, worker = true, buildParams = {} } = {}) {
442
+ export async function build() {
434
443
  const $context = this;
435
- if (!($context instanceof Context)) {
436
- throw new Error(`The "this" context must be a Webflo Context object.`);
444
+ if (!($context instanceof CLIContext)) {
445
+ throw new Error(`The "this" context must be a Webflo CLIContext object.`);
437
446
  }
438
- // Resolve common details
439
- const $config = {
440
- LAYOUT: await readLayoutConfig($context),
441
- ENV: { ...await readEnvConfig($context), data: {} },
442
- CLIENT: await readClientConfig($context),
443
- WORKER: await readWorkerConfig($context),
444
- };
445
- if ($config.CLIENT.copy_public_variables) {
446
- const publicEnvPattern = /(?:^|_)PUBLIC(?:_|$)/;
447
- for (const key in process.env) {
448
- if (publicEnvPattern.test(key)) {
449
- $config.ENV.data[key] = process.env[key];
450
- }
451
- }
452
- }
453
- // Build
447
+
448
+ const buildParams = {};
454
449
  const outfiles = [];
455
- if (client) {
456
- const documentRoots = scanRoots($config.LAYOUT.PUBLIC_DIR, 'index.html');
457
- const _outfiles = await generateClientScript({ $context, $config, roots: documentRoots, buildParams });
450
+ if ($context.flags.client) {
451
+ const bootstrap = await clientBootstrap($context);
452
+ const _outfiles = await generateClientScript({ $context, bootstrap, buildParams });
453
+ outfiles.push(..._outfiles);
454
+ }
455
+
456
+ if ($context.flags.worker) {
457
+ const bootstrap = await workerBootstrap($context);
458
+ const _outfiles = await generateWorkerScript({ $context, bootstrap, buildParams });
458
459
  outfiles.push(..._outfiles);
459
460
  }
460
- if (worker) {
461
- const applicationRoots = scanRoots($config.LAYOUT.PUBLIC_DIR, 'manifest.json');
462
- const _outfiles = await generateWorkerScript({ $context, $config, roots: applicationRoots, buildParams });
461
+
462
+ if (false) { // TODO: WebfloServer needs to be buildable first
463
+ const bootstrap = await serverBootstrap($context);
464
+ const _outfiles = await generateServerScript({ $context, bootstrap, buildParams });
463
465
  outfiles.push(..._outfiles);
464
466
  }
467
+
465
468
  if (process.send) {
466
469
  process.send({ outfiles });
467
470
  }
471
+
468
472
  return { outfiles };
469
473
  }
package/src/index.js CHANGED
@@ -3,12 +3,14 @@ import * as deployment from './deployment-pi/index.js';
3
3
  import * as runtime from './runtime-pi/index.js';
4
4
  import * as services from './services-pi/index.js';
5
5
  import * as starter from './init-pi/index.js';
6
+ import * as build from './build-pi/index.js';
6
7
 
7
- export { Context } from './Context.js';
8
+ export { CLIContext } from './CLIContext.js';
8
9
  export {
9
10
  config,
10
11
  deployment,
11
12
  runtime,
12
13
  services,
13
14
  starter,
15
+ build,
14
16
  }
@@ -4,7 +4,8 @@ import Path from 'path';
4
4
  import { exec } from 'child_process';
5
5
  import { _toTitle } from '@webqit/util/str/index.js';
6
6
  import { readInitConfig } from '../deployment-pi/util.js';
7
- import { Context } from '../Context.js';
7
+ import { CLIContext } from '../CLIContext.js';
8
+ import * as deployment from '../deployment-pi/index.js';
8
9
 
9
10
  export const desc = {
10
11
  init: 'Generate a preset Webflo starter app.',
@@ -12,9 +13,11 @@ export const desc = {
12
13
 
13
14
  export async function init(projectName = 'my-webflo-app', projectTitle = '', projectDescription = '') {
14
15
  const $context = this;
16
+ //middlewares: [ deployment.origins.webhook ],
15
17
 
16
- if (!($context instanceof Context)) {
17
- throw new Error(`The "this" context must be a Webflo Context object.`);
18
+
19
+ if (!($context instanceof CLIContext)) {
20
+ throw new Error(`The "this" context must be a Webflo CLIContext object.`);
18
21
  }
19
22
 
20
23
  const { flags: FLAGS, logger: LOGGER } = $context;
@@ -5,9 +5,9 @@
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build:html": "oohtml bundle --recursive --outdir=public/assets --auto-embed=app",
8
- "build:js": "webflo generate::client --recursive --outdir=public/assets --auto-embed",
8
+ "build:js": "webflo build --client --worker --server --recursive --outdir=public/assets --auto-embed",
9
9
  "build": "npm run build:html && npm run build:js",
10
- "dev": "webflo start --dev --build-sensitivity=2",
10
+ "dev": "webflo start --dev --build-sensitivity=1",
11
11
  "start": "webflo start"
12
12
  },
13
13
  "dependencies": {
@@ -5,9 +5,9 @@
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "build:html": "oohtml bundle --recursive --outdir=public/assets --auto-embed=app",
8
- "build:js": "webflo generate::client --recursive --outdir=public/assets --auto-embed",
8
+ "build:js": "webflo build --client --worker --server --recursive --outdir=public/assets --auto-embed",
9
9
  "build": "npm run build:html && npm run build:js",
10
- "dev": "webflo start --dev --build-sensitivity=2",
10
+ "dev": "webflo start --dev --build-sensitivity=1",
11
11
  "start": "webflo start"
12
12
  },
13
13
  "dependencies": {
@@ -0,0 +1,38 @@
1
+ import { CLIContext } from '../CLIContext.js';
2
+
3
+ export class AppBootstrap {
4
+
5
+ #json;
6
+ #cx;
7
+ #init;
8
+
9
+ constructor(json = {}) {
10
+ this.#json = json;
11
+ this.#cx = new CLIContext(json.cx || {});
12
+ this.#init = { ...(json.init || {})};
13
+ }
14
+
15
+ // cx
16
+ get cx() { return this.#cx; }
17
+
18
+ // init
19
+ get init() { return this.#init; }
20
+
21
+ // $root
22
+ get $root() { return this.#json.offset || ''; }
23
+
24
+ // $roots
25
+ get $roots() { return this.#json.$roots || []; }
26
+
27
+ // $sparoots
28
+ get $sparoots() { return this.#json.$sparoots || []; }
29
+
30
+ // config
31
+ get config() { return this.#json.config || {}; }
32
+
33
+ // routes
34
+ get routes() { return this.#json.routes || {}; }
35
+
36
+ // middlewares
37
+ get middlewares() { return this.#json.middlewares || []; }
38
+ }