How folder-based Applications are compiled — the manifest, virtual file system, and what the build produces.
|
|
Source files (in your folder or manifest) ↓ Virtual file system (in-memory path map) ↓ esbuild (TypeScript → JS, SCSS → CSS, resolves imports) ↓ HTML assembly (inject styles, scripts, import maps) ↓ Self-contained HTML document
manifest.json Source document. For folder-based Applications, it lives at the root of your folder. For document-based Applications, it's the first JSON code block in the document.{ "id": "my_app_v1", "name": "My Application", "description": "What this does", "bundle": { "format": "esm", "entry": { "html": "/index.html", "script": "/src/main.tsx", "style": "/src/styles.scss" }, "dependencies": { "importMap": { "react": "https://esm.sh/react@18.2.0", "react-dom/client": "https://esm.sh/react-dom@18.2.0/client" } } } }
id | |
name | |
bundle.entry.html |
bundle.entry.script | |
bundle.entry.style | |
bundle.format | 'esm' for ES modules. Omit for IIFE (global variables). |
bundle.files | |
bundle.dependencies |
App.tsx in a sub-folder named components becomes /components/App.tsx.files entries: Virtual paths map directly to source queries. The query format is ?nodeId=<id>&format=plain.files entries override or supplement them. Useful when you need to pull a specific file from outside the folder.Folder on disk → Virtual file system ──────────────── ──────────────────── manifest.json (parsed, excluded) index.html → /index.html src/main.tsx → /src/main.tsx src/App.tsx → /src/App.tsx components/Header.tsx → /components/Header.tsx
import { Header } from './components/Header' resolves to /components/Header.tsx..ts) | ||
.tsx) | ||
.jsx) | ||
.js) | ||
.scss) | ||
.sass) | ||
.css) | ||
.html) |
@import 'variables' resolves to _variables.scss in the virtual file system.format: 'esm'):{ "bundle": { "format": "esm", "dependencies": { "importMap": { "react": "https://esm.sh/react@18.2.0", "react-dom": "https://esm.sh/react-dom@18.2.0", "react-dom/client": "https://esm.sh/react-dom@18.2.0/client", "lucide-react": "https://esm.sh/lucide-react@0.554.0?deps=react@18.2.0" } } } }
<script type="importmap"> into the output HTML. Your code uses normal import statements.{ "bundle": { "dependencies": { "cdn": { "react": { "url": "https://unpkg.com/react@18.2.0/umd/react.production.min.js", "global": "React" } } } } }
<script> tags for each CDN URL and generates a require() shim that maps package names to window globals.<html> <head> <!-- injected: import map or CDN scripts --> <!-- injected: compiled CSS --> </head> <body> <!-- your HTML template content --> <script src="charmiq-bridge.js"></script> <!-- bridge injected --> <script type="module">/* bundled JS */</script> </body> </html>
window.charmiq is available before any of your code runs.?debug=true to your Application URL to see build diagnostics:window.charmiq.debug.buildInfo // Full build metadata window.charmiq.debug.showWarnings() // Log build warnings window.charmiq.debug.openDebugPage() // Open debug dashboard
files map. The manifest only needs entry points:{ "id": "my_folder_app", "name": "My App", "bundle": { "format": "esm", "entry": { "html": "/index.html", "script": "/main.tsx" }, "dependencies": { "importMap": { "react": "https://esm.sh/react@18.2.0", "react-dom/client": "https://esm.sh/react-dom@18.2.0/client" } } } }
App.tsx, styles.scss, utils.ts. The extension is how the build pipeline knows which loader to use.https://esm.sh/react@18.2.0 not https://esm.sh/react. Unpinned CDN URLs can introduce breaking changes silently.<style> tags in your HTML template work fine for simple Applications. Add a SCSS entry point when you need variables, nesting, or multiple stylesheets.window.charmiq.