You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 3a601ee
Browse filesBrowse the repository at this point in the historyBrowse files
perf(build): make the bundle tree-shakeable, additively
Adds named exports beside the default namespace, which is unchanged:
`import { imgproc, matrix_t, U8C1_t } from "@webarkit/jsfeat-next"`. Every
namespace member is exported under the same name and is the same object
(singleton state such as fast_corners' threshold is shared). A Vite 8 app
that only calls imgproc.grayscale drops from 69.6 KB (23.9 KB gzip) via
the default import to 22.9 KB (8.1 KB gzip) via named imports, without
ORB's table, GMS, bfmatcher, the detectors or linalg.
What it took, beyond adding the exports:
- The namespace was the core base class that every module extends, so it
was always bundled, and every `jsfeatNext.orb = ...` assignment on it
kept its module alive. It is now a subclass of the base (inheriting the
constants and VERSION), built in one `@__PURE__ Object.assign(...)`: a
bundle that never reads it drops it whole.
- The singletons are created once in src/singletons.ts, marked @__PURE__,
and shared by the aggregator and the named exports. The two module-level
instances in motion_model.ts and ORB's u_max table are marked too.
- Two build passes: ESM from src/index.ts (default + named), UMD from the
new src/umd.ts (namespace only), so the `jsfeatNext` global and
require() are the namespace itself, as before. "sideEffects": false.
- The declaration build now fails on a .d.ts error: an intermediate
version hit TS4094 and published no jsfeatNext.d.ts while the build
passed.
tests/named-exports.test.ts pins identity and completeness both ways;
tests/build/bundle.test.ts checks the built dist/: UMD shape via require()
and as a <script> global, ESM default and named, and that a named
{ imgproc } bundle has none of the unused modules (verified to fail when
an annotation is removed).
Closes#137
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: AGENTS.md
+2-1Lines changed: 2 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,7 +19,8 @@
19
19
20
20
## Architecture — read this before editing
21
21
22
-
-**One real module per algorithm** under `src/<module>/<module>.ts`, each extending the base class in **`src/core/core.ts`** (constants, data-type helpers, the shared cache). `src/jsfeatNext.ts` is a thin aggregator that only attaches modules to the namespace; `src/index.ts` default-exports the namespace directly.
22
+
-**One real module per algorithm** under `src/<module>/<module>.ts`, each extending the base class in **`src/core/core.ts`** (constants, data-type helpers, the shared cache). `src/jsfeatNext.ts` is a thin aggregator that builds the namespace; `src/index.ts` default-exports the namespace directly and also exports every member by name (#137). The algorithm singletons are created once in `src/singletons.ts`, shared by both. The UMD bundle is built from `src/umd.ts` (namespace only), the ESM bundle from `src/index.ts`.
23
+
-**Keep the bundle tree-shakeable (#137).** The namespace is a subclass of the `core` base, built in one `/* @__PURE__ */ Object.assign(...)`, never by assigning members one by one, and every module-level `new` (singletons, shared helper instances, typed-array tables) is marked `/* @__PURE__ */`. An unannotated one silently puts its module back into every bundle; `tests/build/bundle.test.ts` catches it against the built `dist/`.
23
24
-**Calling convention (since 0.9.0, issue #41):** the 15 algorithm modules (`imgproc`, `math`, `matmath`, `linalg`, `transform`, `fast_corners`, `yape`, `yape06`, `orb`, `optical_flow_lk`, `motion_estimator`, `affine2d`, `homography2d`, `bfmatcher`, `gms`, plus the `cache` pool) are **singleton instances** on the namespace — `jsfeatNext.imgproc.grayscale(...)`, no `new` — matching original jsfeat. The data-structure classes (`matrix_t`, `keypoint_t`, `pyramid_t`, `ransac_params_t`, `match_t`, `pose_t`) remain constructors, and so does `pose_estimator`.
24
25
-**`pose_estimator` is deliberately NOT a singleton and deliberately does not extend `core`.** It is *stateful* — it holds the inverted intrinsics `K⁻¹` — and the public API constructs it with a `K` (`new jsfeatNext.pose_estimator(K)`), which also makes its `intrinsics()` factory reachable as a `static` on the namespace class. It therefore belongs with the constructors above, not with the stateless algorithm singletons. Review tooling has flagged this twice as a rule violation; it is not one, and the reasoning is repeated in the class's own JSDoc.
25
26
-**One shared buffer pool:** all modules borrow scratch buffers from the single `shared_cache` exported by `src/core/core.ts` (public as `jsfeatNext.cache`), exactly like jsfeat's global `jsfeat.cache`. Balance every `get_buffer` with a `put_buffer`.
0 commit comments