How San CLI Works Under the Hood: Core Modules, Processes, and Plugin Architecture

This article provides an in‑depth technical walkthrough of San CLI, covering its core modules, the main and service workflows, the plugin system for commands and services, and detailed code examples such as TaskList and Service implementations, helping developers understand and extend the tool.

Baidu App Technology
Baidu App Technology
Baidu App Technology
How San CLI Works Under the Hood: Core Modules, Processes, and Plugin Architecture

Core Modules

San CLI consists of several core packages: san-cli: the main process and core functionality; san-cli-service: the service layer handling service‑related logic; san-cli-command-init: the command plugin that implements san init; san-cli-plugin-*: generic service plugins; san-cli-utils: utility library usable directly in plugins; san-cli-webpack: common webpack build and dev‑server logic, including custom webpack plugins.

Core Concepts

The architecture revolves around two concepts: processes (main process and service process) and plugins (command plugins and service plugins).

Process :

Main Process : defined in san-cli/index.js. When a user runs a command such as san init, san serve (mapped to npm start), or san build (mapped to npm run build), the corresponding handler is invoked. Some handlers delegate to san-cli-service to enter the service process.

Service Process : defined in san-cli-service/Service.js, mainly handling webpack‑related logic.

Plugin :

Command Plugin : runs in the main process; after the command is parsed, its handler is executed.

Service Plugin : runs in the service process; used to extend webpack build steps.

Overall Workflow (Main Process)

Check Node version.

Check San CLI version.

Create a command instance via san-cli/lib/Commander.js:

Add global options.

Add middleware to set logLevel, NODE_ENV, and augment argv with logging utilities.

Load built‑in commands ( init, serve, build, inspect, ui, etc.).

Load custom commands declared in package.json and sanrc.json.

Trigger the selected command's handler to start execution.

san init Process

The san init command initializes a project by pulling a scaffold repository (remote via Git or local) and then processing the files with vinyl‑fs (the core of Gulp).

Check the target directory and offline package status.

Download the scaffold template from a remote repository (e.g., GitHub) into a cache directory.

Generate the project structure by streaming files from the cache to the destination using vinyl‑fs.

Prompt the user to install dependencies listed in package.json.

Design of san init

The command is implemented in the san-cli-command-init module as a Command plugin. It creates a TaskList instance with four serial tasks and calls run() on it.

TaskList Simplified Source

// 任务列表,4 个任务函数分别对应 san init 的 4 个串行任务
const taskList = [checkStatus, download, generator, installDep];
const tasks = new TaskList(taskList);
// 按任务列表的顺序依次执行任务
tasks.run();

Each task is a function that receives a task object. The framework adds a complete() method to the task, which the task calls when it finishes, allowing TaskList to move to the next task.

TaskList Implementation

class TaskList {
    constructor(taskList) {
        this._taskList = taskList;
        this._index = 0;
    }
    run() {
        const currentTask = this._taskList[this._index];
        currentTask.complete = () => {
            this.next();
        };
        currentTask(currentTask);
    }
    next() {
        this._index++;
        if (this._index >= this._taskList.length) return;
        this.run();
    }
}

Plugin Mechanism

San CLI supports two plugin types.

Command Plugins

Command plugins extend the yargs command system. A typical command plugin exports command, builder, desc, and handler. The command is declared in package.json, and when the CLI runs, it loads the declarations, registers them with yargs, and finally invokes the corresponding handler.

// san-command-hello.js
exports.command = 'hello';
exports.builder = { name: { type: 'string' } };
exports.desc = 'Greet the given object warmly';
exports.handler = argv => {
    console.log(`${argv.name},你好呀!`);
};

Service Plugins

Service plugins are inspired by Vue CLI but differ in registration. San CLI separates command registration (Command plugins) from service logic. A command may trigger the service process, which loads built‑in and user‑defined Service plugins (from sanrc.json or san.config.js), instantiates a PluginAPI for each, and calls their apply method.

Service Workflow (Example: san serve )

Parse the command line and invoke san-cli/commands/serve.handler.

Instantiate Service, passing built‑in plugins and those from sanrc.json.

Call service.run():

Load environment files.

Load project options from san.config.js.

Initialize plugins, then execute webpackChain and webpackConfig callbacks.

Execute the final callback.

Service Implementation (Simplified)

class Service {
    constructor(plugins) {
        this.plugins = this.loadPlugin(plugins); // built‑in + sanrc.json plugins
    }
    run() {
        const projectOptions = this.loadProjectOptions();
        const morePlugins = this.loadPlugin(projectOptions.plugins);
        this.plugins = [...this.plugins, ...morePlugins];
        this.plugins.forEach(plugin => {
            const pluginApi = new PluginAPI();
            plugin.apply(pluginApi);
        });
    }
    loadPlugin() { /* unify plugin formats */ }
    loadProjectOptions() { /* read san.config.js */ }
}

PluginAPI (Simplified)

class PluginAPI {
    configWebpack(fn) {
        // expose a method for Service plugins to modify webpack config
    }
}

Conclusion

The article walks through San CLI’s architecture, showing how the main and service processes cooperate, how plugins are structured, and how the TaskList pattern enables easy extension of commands like san init. Understanding these internals helps developers customize or contribute to San CLI effectively.

CLIfrontend developmentplugin systemSan CLITask Runner
Baidu App Technology
Written by

Baidu App Technology

Official Baidu App Tech Account

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.