xote 7.1.0-beta.2 → 7.1.0-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xote",
3
- "version": "7.1.0-beta.2",
3
+ "version": "7.1.0-beta.3",
4
4
  "repository": {
5
5
  "url": "https://github.com/brnrdog/xote"
6
6
  },
@@ -63,10 +63,13 @@
63
63
  "rescript.json",
64
64
  "ppx/ppx.ml",
65
65
  "ppx/build.sh",
66
+ "ppx/postinstall.js",
67
+ "ppx/bin",
66
68
  "ppx/README.md",
67
69
  "ppx/LICENSE.OCaml"
68
70
  ],
69
71
  "scripts": {
72
+ "postinstall": "node ppx/postinstall.js",
70
73
  "res:build": "rescript",
71
74
  "res:clean": "rescript clean",
72
75
  "res:dev": "rescript -w",
package/ppx/README.md CHANGED
@@ -5,15 +5,18 @@ props-deriving component whose returned JSX is decomposed into **fine-grained
5
5
  reactive leaves** — the compile-time counterpart to the runtime
6
6
  [`View.tracked`](../src/View.res) helper.
7
7
 
8
- > **Status:** experimental, opt-in. The PPX is exercised in CI and used by the
9
- > [docs site](../docs-website) itself (the Counter demo), but it is **not part
10
- > of the published npm package** consumers who want it build it themselves
11
- > (see [Opt-in for consumers](#opt-in-for-consumers)). It demonstrates that the
8
+ > **Status:** the standard authoring model. The npm package ships the PPX as a
9
+ > prebuilt binary per platform, selected at install time (see
10
+ > [Distribution](#distribution)), so enabling `@xote.component` is a single
11
+ > `ppx-flags` line with no toolchain requirement. The PPX is exercised in CI
12
+ > and used by the [docs site](../docs-website) itself. It grew out of the
12
13
  > [`rescript-signals` #34](https://github.com/brnrdog/rescript-signals/pull/34)
13
- > auto-tracking idea can target Xote's view layer *and* compile away the
14
+ > auto-tracking idea, targeting Xote's view layer *and* compiling away the
14
15
  > wholesale-replacement tradeoff of `View.tracked`. See
15
16
  > [`docs/proposals/tracked-blocks.md`](../docs/proposals/tracked-blocks.md) for
16
- > the full design context (this is "Phase 2, fine-grained variant").
17
+ > the full design context, and
18
+ > [RFC #141](https://github.com/brnrdog/xote/issues/141) for the decision to
19
+ > distribute prebuilt binaries and make this the primary model.
17
20
 
18
21
  ## What problem it solves
19
22
 
@@ -207,41 +210,58 @@ exception**; they keep their original copyright headers. The
207
210
  and license text is in [`LICENSE.OCaml`](./LICENSE.OCaml), which ships in the
208
211
  npm tarball alongside `ppx.ml`.
209
212
 
210
- ## Build
213
+ ## Distribution
211
214
 
212
- ```sh
213
- sh build.sh # produces ./ppx (needs ocamlopt; any recent OCaml, tested 4.14)
214
- ```
215
+ The npm package ships the PPX **prebuilt** for the common platforms, under
216
+ `ppx/bin/`:
215
217
 
216
- Wire it into a project's `rescript.json`:
218
+ | Platform | Binary |
219
+ |---|---|
220
+ | Linux x64 | `ppx-linux-x64.exe` |
221
+ | Linux arm64 | `ppx-linux-arm64.exe` |
222
+ | macOS x64 (Intel) | `ppx-darwin-x64.exe` |
223
+ | macOS arm64 (Apple Silicon) | `ppx-darwin-arm64.exe` |
224
+ | Windows x64 | `ppx-win32-x64.exe` |
225
+
226
+ The binaries are compiled in CI by
227
+ [`.github/workflows/ppx-binaries.yml`](../.github/workflows/ppx-binaries.yml)
228
+ and injected into the tarball by the release workflow. On install, Xote's
229
+ `postinstall` script ([`postinstall.js`](./postinstall.js)) copies the binary
230
+ matching `process.platform`-`process.arch` to `ppx/ppx` (`ppx/ppx.exe` on
231
+ Windows), which is the path consumers reference:
217
232
 
218
233
  ```json
219
- { "ppx-flags": ["xote-tracked-ppx/ppx"] }
234
+ { "ppx-flags": ["xote/ppx/ppx"] }
220
235
  ```
221
236
 
222
- ## Opt-in for consumers
237
+ That one line in your `rescript.json` is the whole setup — no OCaml toolchain
238
+ required. Two edge cases:
223
239
 
224
- The compiled binary is platform-specific and is **not** shipped in the npm
225
- package, and deliberately neither is a `ppx-flags` entry in Xote's own
226
- published `rescript.json`. That last point matters: a ReScript consumer
227
- recompiles a dependency's sources during its own build and applies that
228
- dependency's `ppx-flags`, so a PPX listed in Xote's published config would
229
- force `ocamlopt` on **every** Xote user. Instead the PPX is strictly opt-in.
240
+ - **Install scripts disabled.** Some package managers skip dependency install
241
+ scripts (pnpm does by default). Approve them for `xote`
242
+ (`pnpm approve-builds`) or run `node node_modules/xote/ppx/postinstall.js`
243
+ once.
244
+ - **Unsupported platform.** If no prebuilt binary matches, the install script
245
+ falls back to compiling `ppx.ml` from source when `ocamlopt` is on the
246
+ `PATH`, and otherwise prints instructions without failing the install.
230
247
 
231
- The `ppx.ml` source *is* published, so a consumer who wants `@xote.component`
232
- can build it from the installed package and reference it from **their own**
233
- `rescript.json`:
248
+ A `ppx-flags` entry is deliberately **not** in Xote's own published
249
+ `rescript.json`: a ReScript consumer recompiles a dependency's sources during
250
+ its own build and applies that dependency's `ppx-flags`, and Xote's `src/`
251
+ carries no `@xote.component` annotations, so listing the PPX there would make
252
+ every build depend on the binary for no benefit. The annotation applies to
253
+ *your* components, which is why the flag lives in *your* `rescript.json` —
254
+ exactly like the `jsx` configuration you already mirror.
234
255
 
235
- ```sh
236
- npm install xote
237
- sh node_modules/xote/ppx/build.sh # needs ocamlopt
238
- ```
256
+ ## Build from source
239
257
 
240
- ```json
241
- { "ppx-flags": ["xote/ppx/ppx"] }
258
+ ```sh
259
+ sh build.sh # produces ./ppx (needs ocamlopt; any recent OCaml, tested 4.14)
242
260
  ```
243
261
 
244
- Consumers who don't do this are entirely unaffected.
262
+ `build.sh` also accepts an output path relative to `ppx/`
263
+ (`sh build.sh bin/ppx-linux-x64.exe`), which is how the CI matrix produces
264
+ the prebuilt binaries.
245
265
 
246
266
  ## In this repo
247
267
 
@@ -272,7 +292,7 @@ Or step by step from `example/`:
272
292
  sh setup.sh # link toolchain + Xote from the repo root (idempotent)
273
293
  sh ../build.sh # build the ppx
274
294
  npm run build # compile Demo.res through the ppx
275
- npm run verify # jsdom runtime check (60 assertions)
295
+ npm run verify # jsdom runtime check (71 assertions)
276
296
  ```
277
297
 
278
298
  ## Known limitations (it's a prototype)
package/ppx/build.sh CHANGED
@@ -1,10 +1,17 @@
1
1
  #!/bin/sh
2
- # Compiles the fine-grained @tracked ppx to a native binary using the system
3
- # OCaml compiler. ReScript 12 hands a ppx an OCaml 4.06 parsetree; ppx.ml
4
- # vendors those exact AST types, so the only build dependency is ocamlopt
5
- # (any recent OCaml works — tested with 4.14).
2
+ # Compiles the fine-grained @xote.component ppx to a native binary using the
3
+ # system OCaml compiler. ReScript 12 hands a ppx an OCaml 4.06 parsetree;
4
+ # ppx.ml vendors those exact AST types, so the only build dependency is
5
+ # ocamlopt (any recent OCaml works — tested with 4.14).
6
+ #
7
+ # Usage: build.sh [output-path]
8
+ # output-path is relative to this directory and defaults to ./ppx.
9
+ # CI passes bin/ppx-<platform>-<arch>.exe to produce the prebuilt binaries
10
+ # shipped in the npm package.
6
11
  set -e
7
12
  cd "$(dirname "$0")"
8
- ocamlopt -w -a-31 ppx.ml -o ppx
13
+ out="${1:-ppx}"
14
+ mkdir -p "$(dirname "$out")"
15
+ ocamlopt -w -a-31 ppx.ml -o "$out"
9
16
  rm -f ppx.cmi ppx.cmx ppx.o
10
- echo "built $(pwd)/ppx"
17
+ echo "built $(pwd)/$out"
@@ -0,0 +1,57 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ * Selects the prebuilt @xote.component ppx binary for the current platform.
4
+ *
5
+ * The npm package ships one native binary per supported platform under
6
+ * ppx/bin/ (built in CI, see .github/workflows/ppx-binaries.yml). This script
7
+ * copies the matching one to ppx/ppx (ppx/ppx.exe on Windows), which is the
8
+ * path consumers reference from their rescript.json:
9
+ *
10
+ * "ppx-flags": ["xote/ppx/ppx"]
11
+ *
12
+ * Fallbacks, in order:
13
+ * 1. No prebuilt binary for this platform, but ocamlopt is available:
14
+ * compile from the bundled ppx.ml source (build.sh).
15
+ * 2. Otherwise: print instructions and exit 0. The install never fails —
16
+ * the ppx is only needed by projects that list it in their own
17
+ * ppx-flags, and Xote's published library sources compile without it.
18
+ */
19
+ 'use strict';
20
+
21
+ const fs = require('fs');
22
+ const path = require('path');
23
+ const { spawnSync } = require('child_process');
24
+
25
+ const ppxDir = __dirname;
26
+ const isWindows = process.platform === 'win32';
27
+ const target = `${process.platform}-${process.arch}`;
28
+ const prebuilt = path.join(ppxDir, 'bin', `ppx-${target}.exe`);
29
+ const dest = path.join(ppxDir, isWindows ? 'ppx.exe' : 'ppx');
30
+
31
+ function installPrebuilt() {
32
+ if (!fs.existsSync(prebuilt)) return false;
33
+ fs.copyFileSync(prebuilt, dest);
34
+ if (!isWindows) fs.chmodSync(dest, 0o755);
35
+ console.log(`xote: installed prebuilt ppx binary for ${target}`);
36
+ return true;
37
+ }
38
+
39
+ function buildFromSource() {
40
+ const probe = spawnSync('ocamlopt', ['-version'], { stdio: 'ignore', shell: isWindows });
41
+ if (probe.error || probe.status !== 0) return false;
42
+ console.log(`xote: no prebuilt ppx binary for ${target}, compiling from source...`);
43
+ const build = spawnSync('sh', [path.join(ppxDir, 'build.sh')], { stdio: 'inherit' });
44
+ return build.status === 0 && fs.existsSync(dest);
45
+ }
46
+
47
+ if (!installPrebuilt() && !buildFromSource()) {
48
+ console.warn(
49
+ [
50
+ `xote: no ppx binary available for ${target}.`,
51
+ 'The @xote.component annotation needs it; the rest of Xote does not.',
52
+ 'To use it, install an OCaml compiler (ocamlopt) and run:',
53
+ ' sh node_modules/xote/ppx/build.sh',
54
+ 'Supported prebuilt platforms: linux-x64, linux-arm64, darwin-x64, darwin-arm64, win32-x64.',
55
+ ].join('\n'),
56
+ );
57
+ }