From 81d4303314fd9bc38e83c189794f5dd25eb632f7 Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Thu, 13 Aug 2026 13:30:16 -0400 Subject: [PATCH 1/8] build: mark the package as ESM Adding "type": "module" flips Vite's default output extensions (.js for ES, .umd.cjs for UMD) and its default CSS asset names. Pin fileName and cssFileName in all three configs so the published artifact names (index.mjs, vtk.umd.js, viewer.umd.js, viewer.css) stay exactly as the exports map and script-tag consumers expect. --- package.json | 1 + vite.config.js | 8 ++++++++ vite.config.standalone.js | 5 ++++- vite.config.viewer.js | 5 ++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index da794f6..dc6ab24 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "@kitware/vtk-wasm", + "type": "module", "version": "0.0.0", "description": "A WebAssembly port of the VTK library", "license": "Apache-2.0", diff --git a/vite.config.js b/vite.config.js index e6c93f4..78832ed 100644 --- a/vite.config.js +++ b/vite.config.js @@ -7,6 +7,14 @@ export default { viewer: "src/viewer.js", }, formats: ["es"], + // "type": "module" flips Vite's default ES extension to .js; keep the + // published .mjs contract (package.json exports point at index.mjs). + fileName: (format, entryName) => `${entryName}.mjs`, + }, + rollupOptions: { + output: { + chunkFileNames: "[name]-[hash].mjs", + }, }, assetsDir: ".", outDir: "./dist/esm", diff --git a/vite.config.standalone.js b/vite.config.standalone.js index efb0613..768a4eb 100644 --- a/vite.config.standalone.js +++ b/vite.config.standalone.js @@ -5,7 +5,10 @@ export default { entry: "src/index.js", formats: ["umd"], name: "vtkwasm", - fileName: "vtk", + // "type": "module" flips Vite's default UMD extension to .umd.cjs; keep + // the published vtk.umd.js name (script-tag consumers, exports map). + fileName: () => "vtk.umd.js", + cssFileName: "vtk", }, assetsDir: ".", outDir: "./dist/umd", diff --git a/vite.config.viewer.js b/vite.config.viewer.js index 1178e42..069e358 100644 --- a/vite.config.viewer.js +++ b/vite.config.viewer.js @@ -5,7 +5,10 @@ export default { entry: "src/viewer.js", formats: ["umd"], name: "vtkWASMViewer", - fileName: "viewer", + // "type": "module" flips Vite's default UMD extension to .umd.cjs; keep + // the published viewer.umd.js name (script-tag consumers, exports map). + fileName: () => "viewer.umd.js", + cssFileName: "viewer", }, assetsDir: ".", outDir: "./dist/umd", From 31fba12c9d09d180df0199138477c97c79baf3ec Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Thu, 13 Aug 2026 13:32:31 -0400 Subject: [PATCH 2/8] refactor(proxy)!: prefix proxy plumbing members with $ Every unprefixed plumbing member (id, obj, set, observe, unObserve, unObserveAll, userData, state, delete) shadowed the C++ member of the same name, making those VTK methods unreachable through the proxy. $ is not a legal character in C++ identifiers, so the prefix guarantees no future collision. toJSON/toString stay unprefixed because JSON.stringify and string coercion look them up by exactly those names. BREAKING CHANGE: proxy plumbing members are now $-prefixed, e.g. actor.delete() becomes actor.$delete() and camera.state becomes camera.$state. --- docs/guide/js/primer.md | 30 ++++++++++----------- docs/guide/js/remote-session.md | 4 +-- examples/trame/widget/clip_rendering.py | 6 ++--- src/core/proxy.js | 35 ++++++++++++++----------- src/remoteSession.js | 2 +- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/docs/guide/js/primer.md b/docs/guide/js/primer.md index c09ddc5..1e537c1 100644 --- a/docs/guide/js/primer.md +++ b/docs/guide/js/primer.md @@ -69,30 +69,30 @@ Once you have an object, inspection usually comes next. Use `toString()` to invo const camera = vtk.vtkCamera(); // directly calls C++ vtkObject::Print() console.log(camera.toString()); -console.log(camera.state); +console.log(camera.$state); // console.log("Camera proxy: ", camera.proxy); -The second `console.log` prints `camera.state` instead of `camera` because objects created through the `vtk` namespace are returned as JavaScript `Proxy` instances. In browser developer tools, the `state` property provides the most useful serialized view of that proxy. +The second `console.log` prints `camera.$state` instead of `camera` because objects created through the `vtk` namespace are returned as JavaScript `Proxy` instances. In browser developer tools, the `$state` property provides the most useful serialized view of that proxy. Proxy plumbing members are `$`-prefixed so they never shadow a C++ property or method of the same name. The full proxy structure looks like this. Uncomment the last line to inspect it in the developer console: ```js -Proxy(Object) {id: 1, obj: {…}, set: ƒ, observe: ƒ, toJSON: ƒ, …} +Proxy(Object) {$id: 1, $obj: {…}, $set: ƒ, $observe: ƒ, toJSON: ƒ, …} [[Handler]] : Object - get : get(d,h,O){return d[h]!==void 0?d[h]:d.userData[h]!==void 0?d.userData[h]:h==="then"?O:h==="state"?e.get?V(e.get(n)):(e.updateStateFromObject(n),V(e.getState(n))):h==="delete"?a:l[h]?l[h]():(d[h]=async(...Ee)=> {…} + get : get(d,h,O){return d[h]!==void 0?d[h]:d.$userData[h]!==void 0?d.$userData[h]:h==="then"?O:h==="$state"?e.get?V(e.get(n)):(e.updateStateFromObject(n),V(e.getState(n))):h==="$delete"?a:l[h]?l[h]():(d[h]=async(...Ee)=> {…} set : ƒ set(d,h,O) [[Prototype]] : Object [[Target]] : Object - id : 1 - obj : {Id: 1} - observe : ƒ p(d,h) - set : ƒ S(d) + $id : 1 + $obj : {Id: 1} + $observe : ƒ p(d,h) + $set : ƒ S(d) toJSON : ƒ b() toString : ƒ u() - unObserve : ƒ c(d) - unObserveAll : ƒ o() - userData : {} + $unObserve : ƒ c(d) + $unObserveAll : ƒ o() + $userData : {} [[Prototype]] : Object [[IsRevoked]] : false ``` @@ -196,7 +196,7 @@ When an object is no longer needed, call `delete()` to release its external Java
 const vtk = await vtkwasm.ready;
 let actor = vtk.vtkActor();
-actor.delete();
+actor.$delete();
 // console.log(actor.toString()) // prints (null)
 actor = null;
 
@@ -255,7 +255,7 @@ console.log(`Part name: ${actor.partName}`); ## Observers -For interactive workflows, register event handlers with `observe()`. Remove a handler later by passing its returned tag to `object.unObserve()`. +For interactive workflows, register event handlers with `$observe()`. Remove a handler later by passing its returned tag to `object.$unObserve()`.