@maka/meteor-sdk 0.2.12 → 0.2.13

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
@@ -70,13 +70,44 @@ output), the same output `meteor build` produces.
70
70
  ```js
71
71
  await sdk.bundle(project, {
72
72
  outputPath: "/path/to/output",
73
- minifyMode: "production", // default; real minification, can take
74
- // multiple minutes and multiple GB of RAM
75
- // for a cold build -- pass "development"
76
- // for a fast smoke build
73
+ minifyMode: "production", // DEFAULT IS "development" -- pass
74
+ // "production" explicitly for deploys.
75
+ // Real minification can take minutes and
76
+ // multiple GB of RAM on a cold build.
77
+ buildMode: "production", // default; also "development"/"test"
78
+ serverArch: undefined, // default: the build host's arch
79
+ webArchs: undefined, // default: the project's platform list
80
+ programs: "all", // "all" (default) | "server" | "client"
77
81
  });
78
82
  ```
79
83
 
84
+ #### Split server/client bundles (`programs`)
85
+
86
+ `programs: "server"` writes a bundle with no client programs whose
87
+ `programs/server/config.json` still records the *intended*
88
+ `clientArchs`. It boots normally and serves pages with 404 until the
89
+ client programs exist -- webapp logs a note per reload and starts
90
+ serving the moment they appear (process restart, or `SIGHUP`, which
91
+ autoupdate already wires to a client-program reload plus a hot-code
92
+ push to connected browsers).
93
+
94
+ `programs: "client"` writes a standalone client artifact: a `star.json`
95
+ listing only the web programs plus `programs/<arch>/` trees that are
96
+ byte-identical to a full bundle's -- so they are drop-in *siblings* for
97
+ a server bundle. Copy `programs/<arch>` into the server bundle's
98
+ `programs/` directory (never untar the client artifact wholesale over a
99
+ server bundle: its root `star.json` would clobber the server's), or
100
+ point the server at an external location with
101
+ `METEOR_CLIENT_BUNDLE_DIR=/path/to/client-artifact/programs` (honored
102
+ by both webapp's static serving and dynamic `import()`).
103
+
104
+ Swap discipline for live servers: activate a new client release with an
105
+ **atomic symlink flip**, never by copying into the live directory -- a
106
+ half-written `program.json` observed by a reload is a fatal error by
107
+ design. Client-only deploys are for client-safe changes; anything
108
+ touching methods, publications or schemas ships server-first or as a
109
+ full bundle.
110
+
80
111
  ### `createAppRunner(project, options)`
81
112
 
82
113
  Runs an app the way `meteor run` does, with a stoppable handle instead of
@@ -281,8 +312,10 @@ why) if you ever need to diagnose unexpected rebuilds.
281
312
  springboarding/multi-release-per-process.** Out of scope for this SDK.
282
313
  - **`createAppRunner()`/`testRun()` don't manage a Mongo process** -- bring
283
314
  your own `mongoUrl`.
284
- - **`bundle()`'s default `minifyMode: "production"` is slow** -- pass
285
- `"development"` for fast iteration.
315
+ - **`bundle()` defaults to `minifyMode: "development"`** (fast, no real
316
+ minification) -- deploys must pass `"production"` explicitly, and that
317
+ mode is legitimately slow on a cold build. (Earlier revisions of this
318
+ README claimed production was the default; the code never agreed.)
286
319
  - A rare, environment-specific gap, out of scope for this package to
287
320
  fix: a from-scratch install can hit an npm/Windows spawn issue when a
288
321
  dependency needs a native rebuild for the first time.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maka/meteor-sdk",
3
- "version": "0.2.12",
3
+ "version": "0.2.13",
4
4
  "description": "Programmatic Node API over the Meteor build tool (bundle/run/create/etc.) -- for driving Meteor's build system from plain Node code instead of shelling out to a meteor CLI (there isn't one anymore; see README.md). \"dependencies\" is generated by scripts/write-tool-package-json.js from scripts/dev-bundle-tool-package.js at the monorepo root -- do not hand-edit that field, edit that file and re-run the script instead.",
5
5
  "main": "src/index.js",
6
6
  "exports": {
@@ -25,7 +25,7 @@
25
25
  "scripts": {
26
26
  "prepack": "node scripts/prepack.js",
27
27
  "build": "node scripts/prepack.js",
28
- "test": "node --test --test-force-exit --test-concurrency=1 test/exports-map.test.js test/ddp.test.js test/test-run.test.js test/errors.test.js test/load-project.test.js test/bundle.test.js test/create.test.js test/close.test.js test/fiber-stubs.test.js test/esm-passthrough.test.js"
28
+ "test": "node --test --test-force-exit --test-concurrency=1 test/exports-map.test.js test/ddp.test.js test/test-run.test.js test/errors.test.js test/load-project.test.js test/bundle.test.js test/bundle-split.test.js test/create.test.js test/close.test.js test/fiber-stubs.test.js test/esm-passthrough.test.js"
29
29
  },
30
30
  "repository": {
31
31
  "type": "git",
@@ -903,6 +903,18 @@ async function runWebAppServer() {
903
903
  clientArchs.forEach(arch => {
904
904
  generateClientProgram(arch, staticFilesByArch);
905
905
  });
906
+ // A configured arch with no program on disk is legal (split
907
+ // server/client deploy: the client artifact hasn't landed yet)
908
+ // but silent was wrong -- say so once per reload so an operator
909
+ // can tell "not deployed yet" from "deployed to the wrong path".
910
+ clientArchs
911
+ .filter(arch => !(arch in staticFilesByArch))
912
+ .forEach(arch => {
913
+ Log.info(
914
+ 'webapp: no client program for ' + arch + ' yet; ' +
915
+ 'serving begins when it appears (restart or SIGHUP).'
916
+ );
917
+ });
906
918
  WebAppInternals.staticFilesByArch = staticFilesByArch;
907
919
  } catch (e) {
908
920
  Log.error('Error reloading the client program: ' + e.stack);
@@ -940,8 +952,17 @@ async function runWebAppServer() {
940
952
  arch,
941
953
  staticFilesByArch = WebAppInternals.staticFilesByArch
942
954
  ) {
955
+ // METEOR_CLIENT_BUNDLE_DIR relocates the client programs for split
956
+ // server/client deploys (a directory holding <arch>/ program dirs);
957
+ // default is the classic sibling layout. Keep in sync with boot.js's
958
+ // dynamic-import root, which honors the same variable -- and note
959
+ // the ENOENT return below is a FEATURE the split relies on: a
960
+ // server-only bundle boots with clientArchs recorded as intent and
961
+ // starts serving the moment the client artifact lands (restart, or
962
+ // SIGHUP via autoupdate's enqueueVersionsRefresh).
943
963
  const clientDir = pathJoin(
944
- pathDirname(__meteor_bootstrap__.serverDir),
964
+ process.env.METEOR_CLIENT_BUNDLE_DIR ||
965
+ pathDirname(__meteor_bootstrap__.serverDir),
945
966
  arch
946
967
  );
947
968
 
package/src/bundle.js CHANGED
@@ -25,6 +25,19 @@ async function bundle(project, options) {
25
25
  throw new MeteorSdkError("bundle() requires options.outputPath");
26
26
  }
27
27
 
28
+ // Validate BEFORE the expensive build, same spirit as the outputPath
29
+ // check above. 'server' writes a bundle without client programs whose
30
+ // config.json still records the intended clientArchs; 'client' writes
31
+ // a standalone client-only star (no server program, no main.js) whose
32
+ // programs/<arch> trees are drop-in siblings for a server bundle.
33
+ const programs = options.programs || "all";
34
+ if (!["all", "server", "client"].includes(programs)) {
35
+ throw new MeteorSdkError(
36
+ "bundle() options.programs must be 'all', 'server' or 'client' " +
37
+ "(got " + JSON.stringify(options.programs) + ")"
38
+ );
39
+ }
40
+
28
41
  const bundler = require("../tools/isobuild/bundler.js");
29
42
 
30
43
  const result = await bundler.bundle({
@@ -35,6 +48,7 @@ async function bundle(project, options) {
35
48
  buildMode: options.buildMode || "production",
36
49
  serverArch: options.serverArch,
37
50
  webArchs: options.webArchs,
51
+ programs,
38
52
  },
39
53
  });
40
54
 
@@ -3300,6 +3300,12 @@ Find out more about Meteor at meteor.com.
3300
3300
  * of debugOnly, prodOnly and testOnly packages, default 'production'
3301
3301
  * - webArchs: array of 'web.*' options to build (defaults to
3302
3302
  * projectContext.platformList.getWebArchs())
3303
+ * - programs: 'all' (default), 'server' or 'client'. 'server' writes a
3304
+ * bundle without client programs whose config.json still records the
3305
+ * intended clientArchs (webapp serves them when the client artifact
3306
+ * arrives at the sibling path); 'client' writes a standalone
3307
+ * client-only star -- programs/<arch> trees byte-identical to a full
3308
+ * bundle's, no server program, no main.js.
3303
3309
  * - warnings: a MessageSet of linting messages or null if linting
3304
3310
  * wasn't performed at all (either disabled or lack of linters).
3305
3311
  *
@@ -3364,6 +3370,16 @@ async function bundle({
3364
3370
  }
3365
3371
  const minifyMode = buildOptions.minifyMode || 'development';
3366
3372
  const buildMode = buildOptions.buildMode || 'production';
3373
+ // Which programs to build and write: 'all' (default), 'server' (skip
3374
+ // the client targets but still record the INTENDED clientArchs in
3375
+ // programs/server/config.json, so webapp serves them once the client
3376
+ // artifact arrives -- missing-at-boot is already tolerated, see
3377
+ // webapp_server.js generateClientProgram's ENOENT path), or 'client'
3378
+ // (skip the server target; writeSiteArchive already gates main.js,
3379
+ // README and config.json on targets.server, so the client-only
3380
+ // artifact falls out honest: a star.json listing only web archs plus
3381
+ // programs/<arch>/ trees byte-identical to a full bundle's).
3382
+ const programs = buildOptions.programs || 'all';
3367
3383
 
3368
3384
  var releaseName =
3369
3385
  release.current.isCheckout() ? "none" : release.current.name;
@@ -3389,6 +3405,11 @@ async function bundle({
3389
3405
  throw new Error('Unrecognized build mode: ' + buildMode);
3390
3406
  }
3391
3407
 
3408
+ if (! ['all', 'server', 'client'].includes(programs)) {
3409
+ throw new Error('Unrecognized programs selection: ' + programs +
3410
+ " (expected 'all', 'server' or 'client')");
3411
+ }
3412
+
3392
3413
  var messages = await buildmessage.capture({
3393
3414
  title: "building the application"
3394
3415
  }, async function () {
@@ -3520,13 +3541,25 @@ async function bundle({
3520
3541
  previousBuilders[arch] = written.builder;
3521
3542
  }
3522
3543
 
3523
- // Client
3524
- for (const arch of webArchs) {
3525
- targets[arch] = await makeClientTarget(app, arch, {minifiers});
3544
+ // Client. Skipped entirely for a server-only build -- but note
3545
+ // webArchs itself is NOT emptied: makeServerTarget below still
3546
+ // receives the full list, so programs/server/config.json records
3547
+ // the INTENDED clientArchs and the server will serve those programs
3548
+ // the moment the separately-deployed client artifact appears at the
3549
+ // sibling path (webapp tolerates missing-at-boot; ENOENT skip in
3550
+ // generateClientProgram).
3551
+ if (programs !== 'server') {
3552
+ for (const arch of webArchs) {
3553
+ targets[arch] = await makeClientTarget(app, arch, {minifiers});
3554
+ }
3526
3555
  }
3527
3556
 
3528
- // Server
3529
- if (! hasCachedBundle) {
3557
+ // Server. Skipped for a client-only build: writeSiteArchive already
3558
+ // gates main.js/README/config.json on targets.server, so the
3559
+ // resulting artifact is an honest client-only star -- programs list
3560
+ // holds only web archs, and the program dirs are byte-identical to
3561
+ // a full bundle's (drop-in compatible as siblings).
3562
+ if (! hasCachedBundle && programs !== 'client') {
3530
3563
  targets.server = await makeServerTarget(app, webArchs);
3531
3564
  }
3532
3565
 
@@ -207,9 +207,18 @@ var specialArgPaths = {
207
207
  var clientArchs = configJson.clientArchs ||
208
208
  Object.keys(configJson.clientPaths);
209
209
 
210
+ // METEOR_CLIENT_BUNDLE_DIR relocates the CLIENT programs (split
211
+ // server/client deploys -- a directory containing <arch>/ program
212
+ // dirs). Must agree with webapp_server.js's generateClientProgram,
213
+ // which honors the same variable: dynamic-import fetches modules
214
+ // from disk independently of webapp's static file map, so missing
215
+ // this one silently breaks import() while pages still serve.
216
+ var clientProgramsDir =
217
+ process.env.METEOR_CLIENT_BUNDLE_DIR || programsDir;
218
+
210
219
  clientArchs.forEach(function (arch) {
211
220
  dynamicImportInfo[arch] = {
212
- dynamicRoot: path.join(programsDir, arch, "dynamic")
221
+ dynamicRoot: path.join(clientProgramsDir, arch, "dynamic")
213
222
  };
214
223
  });
215
224