Skip to content

fix: resolve ES module bare specifiers in widget iframe#51

Merged
GeneralJerel merged 3 commits intomainfrom
fix/save-template-overlay-iframe
Mar 25, 2026
Merged

fix: resolve ES module bare specifiers in widget iframe#51
GeneralJerel merged 3 commits intomainfrom
fix/save-template-overlay-iframe

Conversation

@GeneralJerel
Copy link
Collaborator

Summary

  • Import map added to the widget iframe shell, mapping three, gsap, d3, and chart.js to esm.sh CDN URLs so bare specifiers like import "three" resolve correctly in the sandboxed srcdoc iframe
  • Module auto-detection in the bridge script — dynamically injected <script> tags containing import/export syntax are automatically promoted to type="module" so the import map applies even when the LLM omits the type attribute
  • Skill instructions updated — Three.js guidance now prefers the ES module pattern (import * as THREE from 'three') over the legacy r128 UMD script tag

Test plan

  • Run pnpm dev and ask the agent to create a Three.js 3D visualization
  • Verify the 3D scene renders without Failed to resolve module specifier "three" console errors
  • Verify both ESM (import * as THREE from 'three') and UMD (<script src="cdnjs...">) patterns work
  • Verify other widget types (charts, SVG diagrams) still render correctly

🤖 Generated with Claude Code

GeneralJerel and others added 2 commits March 25, 2026 07:32
The async useState+useEffect refactor caused matchedTemplate to change after first render, inserting a badge div before the iframe and shifting its child index. React reconciles by position, so this remounted the iframe and destroyed rendered 3D/canvas content. Restores the original synchronous ref with eslint-disable comments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add import map to iframe shell mapping common libraries (three, gsap, d3, chart.js) to esm.sh CDN URLs so bare specifiers like `import "three"` resolve correctly. Auto-detect ES module syntax in dynamically injected scripts and promote them to type="module" when import/export statements are present. Update skill instructions to prefer the ES module pattern for Three.js.
References issue #3 — allow-same-origin is required for import maps in srcdoc iframes but weakens the sandbox. Document the tradeoff.
Copy link
Collaborator Author

@GeneralJerel GeneralJerel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Notes

sandbox allow-same-origin (addressed)

allow-scripts + allow-same-origin effectively negates the iframe sandbox — the iframe can access window.parent, DOM, cookies, etc. For this demo (no auth, no client-side secrets) the practical risk is low. Added a code comment referencing issue #3 and posted investigation context there (blob URLs, sandbox subdomain as alternatives).

Auto-detect regex may false-positive

The module auto-detection regex at widget-renderer.tsx:433:

/\b(import\s|export\s|import\()/.test(scriptInfo.text)

matches inside comments and strings (e.g. // We don't import anything), which would promote a non-module script to type="module" — changing execution semantics (strict mode, deferred execution, this is undefined). Consider anchoring to start-of-line or only promoting when a mapped bare specifier is present.

useMemo with ref (minor)

sourceRef.current is read inside useMemo in save-template-overlay.tsx but isn't a dependency. Works for the initial-render capture case, but if pending arrives after mount the memo won't recompute. If late arrivals aren't possible, a comment noting that assumption would help.

Looks good otherwise

  • Import map placement before CSP meta is correct
  • esm.sh already in CSP script-src and connect-src
  • SKILL.md update guiding LLM toward type="module" reduces reliance on auto-detect
@GeneralJerel GeneralJerel merged commit 38e8c5e into main Mar 25, 2026
10 checks passed
@GeneralJerel GeneralJerel deleted the fix/save-template-overlay-iframe branch March 25, 2026 18:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant