diff --git a/packages/react-lang/package.json b/packages/react-lang/package.json index 58a410073..19a1dcf5f 100644 --- a/packages/react-lang/package.json +++ b/packages/react-lang/package.json @@ -1,6 +1,6 @@ { "name": "@openuidev/react-lang", - "version": "0.2.14", + "version": "0.2.15", "description": "Define component libraries, generate LLM system prompts, and render streaming OpenUI Lang output in React — the core runtime for OpenUI generative UI", "license": "MIT", "type": "module", @@ -82,7 +82,6 @@ }, "author": "engineering@thesys.dev", "dependencies": { - "@openuidev/devtools": "workspace:^", "@openuidev/lang-core": "workspace:^", "@openuidev/observability": "workspace:^" }, diff --git a/packages/react-lang/src/devtoolsBootstrap.ts b/packages/react-lang/src/devtoolsBootstrap.ts index 4654e036c..177f367c9 100644 --- a/packages/react-lang/src/devtoolsBootstrap.ts +++ b/packages/react-lang/src/devtoolsBootstrap.ts @@ -3,9 +3,10 @@ * * This module runs as a top-level side effect when the web entry is loaded in * a browser. In production builds the whole block is dead-code-eliminated by - * the consumer's bundler (the NODE_ENV condition folds to false), so neither - * `@openuidev/devtools` nor `react-dom/client` enters the production graph. - * The React Native entry (index.native.ts) never imports this module. + * the consumer's bundler (the NODE_ENV condition folds to false), so + * `react-dom` / `react-dom/client` never enter the production graph, and + * nothing is fetched. The React Native entry (index.native.ts) never imports + * this module. * * This module is inlined into the web entry (dist/index.*), which is listed * in package.json's `sideEffects` so bundlers preserve the side effect while @@ -21,15 +22,29 @@ if (process.env.NODE_ENV === "development" && typeof document !== "undefined") { // (ESM/CJS dual build, multiple package versions). if (!flags[AUTO_MOUNT_FLAG]) { flags[AUTO_MOUNT_FLAG] = true; - Promise.all([import("@openuidev/devtools"), import("react"), import("react-dom/client")]) - .then(([devtools, react, reactDomClient]) => { + + // Pinned to the protocol major, not @latest: cached for days, and a + // protocol-breaking release (mount() args, Symbol keys, event kinds) + // would otherwise take down every app that hasn't bumped. + const url = "https://cdn.jsdelivr.net/npm/@openuidev/devtools@0/dist/devtools.browser.js"; + + Promise.all([ + import(/* webpackIgnore: true */ /* @vite-ignore */ url), + import("react"), + import("react-dom"), + import("react-dom/client"), + ]) + .then(([devtools, react, reactDom, reactDomClient]) => { const mount = () => { - const host = document.createElement("div"); - host.setAttribute("data-openui-devtools-root", ""); - document.body.appendChild(host); - reactDomClient - .createRoot(host) - .render(react.createElement(devtools.OpenUIDevtools, { __autoMounted: true })); + devtools.mountOpenUIDevtools({ + React: react, + ReactDOM: reactDom, + ReactDOMClient: reactDomClient, + // Closed over this module's graph so the bundler resolves it — + // the CDN file never imports "@openuidev/react-lang" itself. + loadReactLang: () => import("@openuidev/react-lang"), + __autoMounted: true, + }); }; // Module evaluation can happen before exists (script in ). if (document.body) mount(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 19bf98fb4..25d21eba9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1929,9 +1929,6 @@ importers: packages/react-lang: dependencies: - '@openuidev/devtools': - specifier: workspace:^ - version: link:../devtools '@openuidev/lang-core': specifier: workspace:^ version: link:../lang-core