| name | external-bundle |
| description | Add, use, or migrate a module to the external bundle system in sy-f-misc. Trigger when: user asks to reduce bundle size, move a module to external, use dynamic import for a large module, or asks about @external imports. |
| metadata | {"version":"1.0.0","author":"frostime","reference":".sspec/spec-docs/external-bundle.md"} |
What This Skill Covers
The external bundle system lets you split large/infrequently-used modules out of the main index.js bundle. They are compiled to separate .js files under external/ and loaded at runtime via dynamic import().
Full architecture details โ spec-doc
When to Use External Modules
Use external bundle for a module when all of the following are true:
- Size > ~5 KB (use
pnpm run build + check bundle stats, or estimate from file size)
- Not on the startup critical path (not imported top-level in
index.ts chain)
- Feature is triggered by user action, not automatically on plugin load
- Module is self-contained (doesn't depend heavily on other
src/ internals)
Step-by-Step Workflow
A. Create a New External Module
-
Create the source file in src/external/:
export function myFunction(input: string): string {
return input.trim();
}
export default class MyClass { }
For a directory module:
src/external/my-lib/
index.ts โ entry point
helpers.ts โ internal (bundled into my-lib.js)
-
Register in vite.config.ts:
const EXTERNAL_MODULES = ["sandbox", "text-edit-engine", "my-module"];
-
Import dynamically in business code:
const mod = await import('@external/my-module');
const result = mod.myFunction('hello');
const instance = new mod.default();
-
Verify build: Run pnpm dev or pnpm build, confirm:
dev/external/my-module.js (or dist/external/) is generated
- No warnings about unregistered modules in console
B. Migrate Existing Module to External
-
Move the file:
src/libs/heavy-module.ts โ src/external/heavy-module.ts
-
Register in vite.config.ts EXTERNAL_MODULES array.
-
Update all import sites โ replace static imports with dynamic:
import HeavyModule from '@/libs/heavy-module';
const { default: HeavyModule } = await import('@external/heavy-module');
-
Remove old file from src/libs/ if no longer needed there.
-
For TypeScript types โ use import type at the top (safe, no runtime effect):
import type { MyType } from '@external/heavy-module';
C. Use an Existing External Module
const SandboxModule = await import('@external/sandbox');
const JavaScriptSandBox = SandboxModule.default;
const instance = new JavaScriptSandBox();
await instance.init();
const { doSomething, MyClass } = await import('@external/my-module');
let _sandboxMod: typeof import('@external/sandbox') | null = null;
async function getSandbox() {
_sandboxMod ??= await import('@external/sandbox');
return _sandboxMod;
}
Checklist Before Finishing
Common Mistakes
| Mistake | Effect | Fix |
|---|
import X from '@external/foo' (static) | Plugin removes it, runtime crash | Use await import(...) |
Module not in EXTERNAL_MODULES | Build warning, runtime 404 | Add to config array |
Calling import('@external/foo') at top level | CJS bundle error with top-level await | Move into async function |
External module imports from @/ (main src) | Compile error or missing reference | Copy utility or extract to npm package |
Forgot to save vite.config.ts after adding module | Module not built | Confirm the config change |
Key Files
| File | Role |
|---|
vite.config.ts | EXTERNAL_MODULES list + plugin setup |
vite-plugin-external-modules.ts | Plugin implementation (scan, build, transform) |
src/external/ | Source directory for all external modules |
dev/external/ / dist/external/ | Build output |