Refactor playground module system to support multi-file examples#84
Merged
AgentEnder merged 2 commits intomainfrom Apr 18, 2026
Merged
Refactor playground module system to support multi-file examples#84AgentEnder merged 2 commits intomainfrom
AgentEnder merged 2 commits intomainfrom
Conversation
The playground previously loaded only the entry file and regex-stripped
every non-cli-forge import, so multi-file examples like composable-builders
and multi-command-cli silently broke whenever they did
`import { x } from './commands/build'` — the sub-module identifier became
undefined at runtime.
Replace the single-file ESNext transpile + binding-preamble dance with a
minimal CJS loader: pre-transpile every file reachable from the entry to
CommonJS, walk the require() graph, then execute with a custom require()
that resolves relative specifiers against the in-memory file map and
returns the host `cli-forge` / `@cli-forge/parser` modules for bare
specifiers. Sub-modules run in a plain Function for sync require
semantics; the entry still runs in an AsyncFunction so top-level await
keeps working.
Contributor
|
View your CI Pipeline Execution ↗ for commit 047bfe0
☁️ Nx Cloud last updated this comment at |
Contributor
|
Docs Preview: https://craigory.dev/cli-forge/pr/84/ |
The playground previously only had a Monaco model for the active tab, so
the TypeScript language service couldn't resolve relative imports between
sibling files — `import { buildCommand } from './commands/build'` showed
up as an unresolved specifier even when the file existed in the example.
Capture the monaco namespace during onMount and add a sync effect that
creates / updates / disposes models for every code and JSON file in the
example at `file:///${path}`. The active file stays owned by the Editor
component (so typing still works); sibling models get refreshed when a
different example is loaded. Also flip on `resolveJsonModule` so examples
that import JSON config files get types too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactored the playground code execution engine to support multi-file examples with proper CommonJS module resolution, replacing the previous single-file approach that used regex stripping and a preamble-based import injection system.
Key Changes
Module graph support: Introduced a file map (
codeFileMap) that tracks all code and JSON files, enabling proper module resolution across multiple files in the playground.Pre-transpilation and caching: Implemented
transpileRec()to walk the require graph up-front and transpile all reachable modules to CommonJS before execution, allowing synchronousrequire()calls during runtime.Proper module system: Built a complete CommonJS module loader with:
ModuleRecordtracking for each module's exports and load stateloadSubModule()for lazy-loading sub-modules with circular dependency supportcreateRequire()factory that returns a require function scoped to each module's directoryPath resolution: Added
resolveRelative()utility that implements Node.js-style module resolution, including:dirname(),normalizePath()).ts,.tsx,.js,.jsx,.mjs,.cjs,.json)index.ts,index.js, etc.)Simplified transpilation: Replaced complex regex-based import stripping with straightforward TypeScript transpilation to CommonJS, handling all TS syntax naturally.
Host module wrapping: Wrapped
cli-forgeand@cli-forge/parsermodules to ensure their default exports work correctly with TypeScript's__importDefaulthelper.Entry point rewriting: Moved the
.forge()→.forge(__argv__)rewrite into the transpilation phase for the entry file only.Implementation Details
Functionscope with propermodule,exports,require,__filename, and__dirnamebindings, matching Node.js CJS semantics.AsyncFunctionto support top-level await if needed.module.exports = {...}statements.https://claude.ai/code/session_01B3gDdZJb71jjou2L55vqfk