From cc2a177f208b110cd81a95ea0892674192aa2420 Mon Sep 17 00:00:00 2001 From: Jordan Paulino Date: Thu, 13 Aug 2026 15:58:21 -0400 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=8D=95=20Stop=20component=20client.js?= =?UTF-8?q?=20from=20running=20in=20Kiln=20edit=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Vite pipeline serves the view-mode bootstrap in edit mode, and that bootstrap calls mountComponentModules() at module scope — so every on-page component's client.js executes as soon as the module evaluates, while an editor is in Kiln. The legacy clay compile pipeline resolved client.js for view mode only (the edit branch of getDependencies() ships model.js, kiln.js and kiln plugins, but no client bundle and no _client-init.js), so this is a regression from clay compile. It runs ads (GPT injects an iframe per slot), analytics and comment embeds inside the editing surface, where they mutate the DOM Kiln is trying to decorate. Generate a second entry, .clay/vite-bootstrap-no-mount.js, from the same initializer prelude — the window.modules stub, _env-init, _globals-init and the sticky-events shim, all of which edit mode genuinely needs — but without the mount runtime, and serve that in edit mode. resolveModuleScripts() takes mountInEditMode to opt back in, and falls back to the mounting bootstrap when public/js was built by a claycli predating the new entry. Co-authored-by: Cursor --- CLAY-VITE.md | 40 +++++++++- lib/cmd/vite/generate-bootstrap.js | 122 ++++++++++++++++++++--------- lib/cmd/vite/generators.test.js | 39 +++++++++ lib/cmd/vite/index.js | 77 ++++++++++++++---- lib/cmd/vite/index.test.js | 100 +++++++++++++++++++++++ lib/cmd/vite/scripts.js | 38 ++++++++- 6 files changed, 358 insertions(+), 58 deletions(-) diff --git a/CLAY-VITE.md b/CLAY-VITE.md index 271f8fe..1ebdd9f 100644 --- a/CLAY-VITE.md +++ b/CLAY-VITE.md @@ -442,10 +442,43 @@ absent on the next deploy → old path activates. No code changes needed in the | Aspect | `clay compile` | `clay vite` | |---|---|---| | **How scripts are resolved** | `getDependencies()` reads `_registry.json` | `resolveModuleScripts()` reads `_manifest.json` | -| **Edit mode scripts** | All `_deps-*.js` + `_models-*.js` + `_kiln-*.js` + templates | Single `_kiln-edit-init` bundle + templates | +| **Edit mode scripts** | All `_deps-*.js` + `_models-*.js` + `_kiln-*.js` + templates | `vite-bootstrap-no-mount` + `_kiln-edit-init` bundle + templates | | **View mode scripts** | Numeric IDs → individual dep files | `vite-bootstrap` + `_globals-init` + shared chunks (typically 3–5 files) | +| **Component `client.js` in edit mode** | Never runs — the `edit` branch of `getDependencies()` ships no client bundle and no `_client-init.js` | Never runs — edit mode loads the no-mount bootstrap (see below) | | **Global scripts** | Individual files per registry entry (70–100 requests) | All `global/js/*.js` in one `_globals-init.js` (1 request) | +#### Component `client.js` does not run in edit mode + +Under `clay compile`, component controllers only ran on rendered pages: the `edit` branch of +`getDependencies()` resolves `model.js`, `kiln.js` and kiln plugins, but neither the client +dependency graph nor `_client-init.js` — the runtime that mounts controllers. Editors therefore +never executed component `client.js` inside Kiln. + +`clay vite` preserves that. Two bootstrap entries are generated from the same initializer prelude: + +| Entry | Loaded in | Contents | +|---|---|---| +| `.clay/vite-bootstrap.js` | view mode | prelude + `_clayClientModules` map + `mountComponentModules()` | +| `.clay/vite-bootstrap-no-mount.js` | edit mode | prelude only | + +The prelude (the `window.modules` stub, `_env-init.js`, `_globals-init.js` and the sticky-events +shim) is required in both modes — Kiln's preloader reads `window.modules`, and every `model.js` +and kiln plugin reads env through the object `_env-init.js` hydrates. Only the mount runtime is +view-mode-specific, and it runs at module scope, so serving the view bootstrap in edit mode +executes every on-page component's `client.js`. That fires analytics, ad calls (GPT injects an +`