In the previous chapter, External Editor Delegation, we learned how to pause our CLI to let the user edit files in their favorite text editor.
We have built a robust command. However, imagine if our CLI tool grew from having just 1 command to having 100 commands. If we loaded the code for all 100 commands every time the user typed a single letter, our application would be incredibly slow to start.
In this final chapter, we will explore Lazy Module Loading. This is a performance pattern that keeps your application fast, no matter how big it grows.
Imagine a library with thousands of books.
In our code:
index.ts (Metadata).keybindings.ts (The Logic).We want the CLI to start instantly.
keybindings command (its name and description) immediately.keybindings.ts into memory until the user actually types my-cli keybindings.In JavaScript/TypeScript, there are two ways to import code.
This happens at the very top of a file. The computer loads this file immediately when the program starts.
// โ Don't do this for heavy commands
import { call } from './keybindings.js'
This is a function that you call later. It tells the computer: "Please go get this file now."
// โ
Do this inside a function
const loadCommand = () => import('./keybindings.js')
load Property
Let's look at our menu file, index.ts. This is the only place we need to change to enable Lazy Loading.
We use a specific property called load.
// --- File: index.ts ---
const keybindings = {
name: 'keybindings',
description: 'Open configuration file',
// The Lazy Load Magic:
load: () => import('./keybindings.js'),
} satisfies Command
Explanation:
load: This is a function definition.() => ...: This represents an arrow function. It is not executed yet. It is just sitting there, waiting to be called.import(...): This command will trigger the actual reading of the file from the hard drive.When the CLI starts up:
index.ts.load function, but it does not run it.keybindings.js file entirely.Let's visualize the difference between the startup phase and the execution phase.
You might be wondering: How does the main CLI know how to use this?
While we don't write the framework code in this tutorial, here is a simplified example of what the CLI framework does behind the scenes when a user types a command.
// --- Pseudo-code for the Main CLI Runner ---
async function runCommand(commandName: string) {
// 1. Find the command definition (The Index Card)
const commandDef = allCommands.find(c => c.name === commandName)
// 2. NOW we call the load function (Walk to the shelf)
console.log("Loading module...")
const module = await commandDef.load()
// 3. Run the logic (Read the book)
await module.call()
}
Explanation:
await commandDef.load(): This line pauses the program for a split second while Node.js finds the file and loads it into memory.module variable contains everything exported from keybindings.ts.Congratulations! You have completed the Keybindings Command Tutorial.
Throughout these five chapters, you have built a professional-grade CLI command using best practices:
index.ts) from Logic (keybindings.ts).isEnabled checks, hiding unfinished features from users.wx flag to safely create files without overwriting existing user data.spawn to hand off control to tools like Vim or VS Code.By combining these five patterns, you have created a tool that is safe, fast, and respectful of the user's environment. You are now ready to build complex CLI tools that can scale to hundreds of commands without slowing down.
Happy coding!
Generated by Code IQ