Last time we discussed the use of San CLI. This time we will take a closer look at the implementation of San CLI.

1. Core modules and core concepts

To understand the overall San CLI workflow (main workflow), let’s first look at the core modules and concepts of the San CLI.

1. Core modules

The core modules of the San CLI include:

  • San-cli: responsible for the main flow and core functions of the SAN CLI.

  • San-cli-service: the service layer, responsible for the service process.

  • San-cli-command-init: command plug-in to implement SAN init command.

  • San-cli-plugin -* : Service plugin;

  • San-cli-utils: a utility library that can also be used directly in plug-ins;

  • San-cli-webpack: common logic for Webpack build and dev-server, self-developed plug-ins for Webpack, etc.

2. Core concepts

The core concepts are processes and ** plug-ins. ** Wherein, the process is divided into main process and Service process, plug-in is divided into Command plug-in and Service plug-in:

  • The San CLI process is divided into two parts: main process and Service process:

Main flow: SAN-CLI /index.js flow is the entire SAN CLI workflow. After entering San CLI-related commands, such as San init, San serve (corresponding to NPM start), and San Build (corresponding to NPM run build), the main flow will execute the handler of the corresponding command. Some commands do not directly contain processing logic, but instead introduce SAN-cli-service, such as SAN serve and SAN Build. When entering these commands, the service flow will be entered from the main flow. Service flow: san-cli-service/ service. js flow, which mainly deals with Webpack build related logic.

  • Plug-ins: to extend the functionality of the San CLI:

Command plug-in: used for the main process. After executing the Command defined by the Command plug-in, the main process executes the hanlder of the corresponding Command plug-in. Service plug-in: For Service flow, handling Webpack build-related logic.

Second, the overall work process

The overall workflow of the San CLI, that is, the main workflow, is as follows in SAN-cli /index.js:

  1. Check the Node version.

  2. Check the SAN-CLI version.

  3. Create a command instance by calling san-cli/lib/ commander.js:

  4. Add global option;

  5. Add middleware:

  6. Set global logLevel.

  7. Set the NODE_ENV environment variable;

  8. Add properties and methods such as logging to argv.

  9. Load built-in commands: init, serve, build, inspect, UI, etc.

  10. Load preset commands (custom commands) declared in package.json and sanrc.json;

  11. Json is the configuration file of the San CLI. It is different from san.config.js, which is the configuration file of the San CLI.

  12. Trigger command hanlder to start the formal execution of the San CLI.

The main process of combining core modules is shown in the figure below:

Third, SAN init

The SAN init command is used to initialize a project. The use of this command was described in the previous installment. In this installment, we will look at how this command does this.

1. The process

SAN init initializes a project by using git commands to pull the scaffolding template’s code base locally or directly using the scaffold template’s code base locally and then using vinyl-fs to process the pulled code base files in sequence. When the processing is complete, you have an initialized project.

Vinyl-fs is at the heart of GULP.

SAN Init consists primarily of four sequential tasks:

  1. Check directory and offline package status: Check whether the local path and offline package of the project scaffold template are available.

  2. Download project scaffolding templates: Download project scaffolding templates from Github and other remote repositories to template cache directory.

  3. Generate the project directory structure: use vinyl-fs to traverse the project scaffolding template from the cache directory to the developer’s specified project directory;

  4. Install project dependencies: Ask the developer whether to install dependencies in package.json.

The corresponding flow chart is shown in the figure below:

The flowchart for checking the status of directories and offline packages is as follows:

2. Design ideas

SAN CLI-command-init module is a command plug-in, the core of which is a TaskList class. The essence of SAN init execution process is as follows: Instantiate the TaskList by passing in an array of the four tasks above and calling the instance’s run method.

Let’s take a look at the internal implementation of TaskList.

When the run method of a TaskList instance is called, the first task on the TaskList passed in when the TaskList is instantiated is processed first.

Because these tasks are essentially functions, add some methods to the first task, such as a complete method to indicate that the task is complete, and then call the first task function.

Calling the first task function means that the first task has started to execute. When the first task has done everything, the complete method added to the task function will be called in this task function.

The complete method does just one thing and lets the TaskList instance start processing the next task, doing the same as above, but simply repeating.

Finally, the TaskList instance finds that there is no next task and calls it a day.

3. TaskList source simplified version

Let’s use a simplified version of the source code to look at the use and implementation of TaskList.

Use of TaskList:

Take checkStatus as an example to look at the implementation of the task function:

TaskList implementation:

For example, if we want to add an additional task to SAN init, we just need to implement the task itself and put it into the TaskList passed in when instantiating TaskList. This is very scalable.

4. Plug-in mechanism

The San CLI plug-in is divided into Command plug-in and Service plug-in. In the last episode, we discussed how to develop a Command plug-in or Service plug-in. In this episode, we will look at the San CLI plug-in mechanism.

1. The Command plug-ins

The Command plug-in has a simpler mechanism than the Service plug-in.

The Command plugin is actually an extension of the yargs plugin system, which is an NPM package that allows us to define our own Command line commands.

Review the Command plug-in we created in the previous installment:

I write this because this is what Yargs requires to define a command. Once the command is defined, declare it in your project’s package.json.

When we execute any SAN command — any command, mind you — the SAN CLI reads the command declared in package.json before actually executing the command, finds the definition of the command and passes it to Yargs, and yargs knows what the commands are. After that, San CLI passed the name and parameters of the command we executed as YARgs, and Yargs returned to execute the hanlder of the corresponding command after getting the name and parameters of the command.

This is how the Command plug-in works.

It is also worth noting that in san-cli/lib/commander. Js, a class named Command is defined. This class makes some customizations to the Yargs plug-in, such as adding common methods and attributes to the argv object through middleware mechanisms. This facilitates direct use by downstream handlers.

2. Service plug-in

The Service plug-in mechanism of the San CLI borrows the Service plug-in mechanism of the Vue CLI, with some differences:

  • Vue CLI registers a new command through the Service plug-in to complete, specifically using the Service plug-in registerCommandAPI method to achieve; The San CLI, on the other hand, separates the logic for registering a new Command from the Service plug-in into a separate part, the Command plug-in introduced earlier.

  • A Vue CLI command corresponds to one or more Service plug-ins, that is, the implementation of a command is completed by one or more Service plug-ins. Whereas a San CLI Command corresponds to zero or all Service plug-ins (introduced), a Command corresponds to zero if the Command is a pure Command plug-in, The case where a Command corresponds to all Service plug-ins is when the Command triggers a Service flow in the logic of its corresponding Command plug-in, and the Service flow registers and executes all Service plug-ins in turn.

Below we will take SAN serve command as an example, respectively look at the Service process, Service plug-in design ideas and Service class simplified version of the source code.

1) Service process

The entire workflow of a Service:

  1. San CLI In the main flow parsing, run the San serve command on the CLI to enter the handler of San – CLI/Commands /serve.

  2. The handler of the SAN serve command mainly instantiates Service. The instantiation processes configuration items and Service plug-ins.

  3. Execute service.run(callback) to enter the service process, which is mainly implemented in service.run:

  4. LoadEnv: loads env files.

  5. LoadProjectOptions: load san.config.js;

  6. Init: service starts:

  7. Initialize the plug-ins, that is, execute them in turn;

  8. Execute the webpackChain callback stack in turn;

  9. Execute the webpackConfig callback stack in turn;

  10. Implement the callback.

The corresponding flow chart is as follows:

The specific execution timing of our custom Service plug-in is in the 3-1-1 “initialize plug-ins, execute plug-ins in sequence” step, corresponding to the “initialize plug-ins (plugin. apply)” step in the figure above.

The “initialize plugin variable and load the plugin” step and the “load the plugins in config” step are actually loading the Service plug-in. It’s just that the former is loading built-in plug-ins and default plug-ins in sanrc.json, while the latter is mainly loading plug-ins in san.config.json.

The flowchart for loading the Service plug-in is as follows:

2) Design ideas

Run the SAN serve command to trigger the corresponding handler. A handler does two things: instantiate a Service and call the run method of the Service instance.

When instantiating a Service, the built-in Service plug-in and the default Service plug-in in sanrc.json are loaded. If our custom Service plugin is preset in sanrc.json, such as san-cli-plugin-get-entry, it will be loaded at this point.

When the Service is instantiated, the run method of the Service instance is called.

When we call the run method, we first load the Service plug-in in san.config.js, as well as our custom Service plug-in in san.config.js. Then, the loaded Service plug-ins are all loaded, and you’re ready to execute them in turn.

Before executing each Service plug-in, the PluginAPI is instantiated. PluginAPI instances provide Service plug-ins with methods for handling Webpack build-related logic, such as configWebpack, through which we can retrieve and modify Webpack configurations in the Service plug-in. For example, in the Service plug-in example we wrote last time, we used this method to get the entry file name of a website.

Finally, the execution of the Service plug-in begins by calling the Apply function defined by the Service plug-in with the PluginAPI instance as an input parameter.

3) Service source simplified version

Service usage:

Service implementation:

Implementation of PluginAPI:

Five, the last

Thank you for reading, and that’s how San CLI Works. If you understand, please accept my knees:

In 2021, there will be continuous development and optimization of SAN-CLI, such as eject function, CLI and Service separation. For further updates, please visit GitHub of San CLI. Welcome star, issues and PR.

Address: github.com/ecomfe/san-…

Original link: mp.weixin.qq.com/s/-yhs_86CA…

Baidu Architect

Baidu official technology public number online!

Technical dry goods, industry information, online salon, industry conference

Recruitment information · Internal push information · technical books · Baidu surrounding

Welcome students to pay attention to!