Many projects at work are developed based on umi, so I recently learned the source code of umi, and I have a little more goodwill about this framework~. If you are also interested, welcome to learn or review with me.
This article will take you from the start of project operation, step by step to understand the core part of umi.
After we create the umi project, the first step is generally to use the yarn start
command to run it. The execution is umi dev
, which is the umi command, so let's first see how the umi command is defined.
下面提到的源码目录在 umi 的源码仓库 /packages 目录下。
umi command
The umi command is defined in the /umi/bin
directory and executes /umi/src/cli.ts
by default. The logic is as follows:
1. Parameter normalization
Use the yargs-parser
library to handle command line arguments, and the logic for handling version
, help
commands.
2. [dev] Start a new process
Let's talk about the difference between dev
and build
. The development environment will additionally start a new process to run the service, and do some event monitoring and communication processing.
This part of the code is in /umi/src/utils/fork.ts
, and the core logic mainly consists of three parts:
##### 2.1 Handling port numbers
The default port is 8000, if it is occupied, it will automatically increase by 1.
##### 2.2 Start a new process
Use child_process
of fork
to create a new child process and execute /umi/src/forkedDev.ts
. The logic in this file is the third and fourth steps below.
##### 2.3 Handling Communication
After the child process is created, the events of the child process will be monitored to deliver messages. Two events will be processed here: RESTART
restart and UPDATE_PORT
update port.
The main process (the current process running the umi command) will listen for events such as exit to kill the child process and trigger the onExit
event of the plugin.
3. Initialize webpack
This part of the code is at /umi/src/initWebpack.ts
.
Before initialization, it will go to the configuration file to find out if there is a configuration of webpack5
or mfsu
. If there is, initialize webpack5, if not, initialize webpack4.
An important point to mention here is that umi encapsulates dependencies similar to webpack in deps
. The previous "Umi 4 Design Ideas" speech mentioned the concept of middlemen, and umi will do some pre-packaged work to solve version stability. sexual issues.
4. Construct the Service object
Finally talking about the core part of umi, the code is short but important.
await new Service({ ...params }).run({
name: 'dev', // or 'build'
args,
});
There is a special treatment here. The Service
used for initialization is a small package, and preset-built-in
is built in by default. This preset is the implementation part of the extension method of the plugin.
import { IServiceOpts, Service as CoreService } from '@umijs/core';
class Service extends CoreService {
constructor(opts: IServiceOpts) {
...
super({
...opts,
presets: [
require.resolve('@umijs/preset-built-in'),
...(opts.presets || []),
],
plugins: [require.resolve('./plugins/umiAlias'), ...(opts.plugins || [])],
});
}
}
Plugin is a very important part of umi's design. The idea of plug-in allows umi to easily control the process and implement customization. This idea has an academic name microkernel architecture.
microkernel architecture
This part will not be discussed. I also checked the data and picked up some important points, focusing on understanding the design ideas of the core system. The Service
class is the core system of umi.
Core class Service
The code is in /core/src/Service/Service.ts
. The structure of this class is very simple, with only two parts: the constructor and run()
method.
constructor constructor
The main work of the initialization phase is to collect the configuration. From this, we can see that the author is so careful, the priority of the environment variables, the priority of the configuration file, and even the details of the page(s)
directory name are clearly arranged.
The initialized attributes can be clearly seen from the figure, so I won't go into details. Only the important parts (I think) are listed here.
When initializing presets and plugins, the information of all plugins will be recorded, that is, the plugin registry, so as to facilitate the management and operation of plugins.
run()
run~
To sum it up, this part is going forward by life cycle:
- Initialize presets and plugins
- set some hooks
- Finally, execute
runCommand()
run the specific logic related to the umi command
Service has 9 life cycles, which are used as the basis for judging some actions performed in subsequent plug-ins.
export enum ServiceStage {
uninitialized,
constructor,
init,
initPresets,
initPlugins,
initHooks,
pluginReady,
getConfig,
getPaths,
run,
}
The initialization logic of presets and plugins is the same, and a few important lines of pseudocode are excerpted as follows:
const api = this.getPluginAPI({ id, key, service: this })
// 获取 PluginAPI 对象,用来传递给 plugin 本身,也就是插件的实现规范
this.registerPlugin(preset)
// 插件注册表,执行的代码是 this.plugins[preset.id] = preset
const { presets, plugins } = await this.applyAPI({ api, apply: preset.apply })
// 执行插件内部的 apply 方法,即 return apply()(api)
PluginAPI
This class defines the core method of the Plugin, which has been described in detail in the umi documentation.
applyPlugin()
The core method of plug-in execution, type
in the parameter determines the logic of executing the plug-in, add and modify will add or modify the initialValue, and return the result after running, event exists as an event as the name suggests.
tapable(webpack) I am still learning and summarizing, there are excellent articles welcome to recommend to me~.
runCommand()
Here we mainly look at the logic related to the dev
command, the code is in preset-built-in/src/plugins/commands/dev/dev.ts
.
preset-built-in
This is the default plug-in set of umi, and the functions implemented are mainly divided into five parts:
registorMethods
Unified registration method.
route
Implementation of routes configuration.
write temporary file
The file generation process in the
src/.umi
directory is all here, including the entry, routing, plug-ins, etc. of the project.configure
umi's document configures the implementation in .
commands
The specific implementation logic of the command and the modification of the webpack configuration are related.
Just share it here, please correct me if I am wrong.
refer to
"Ant Front-end R&D Best Practices" Text
"Umi 4 Design Ideas - Yun Qian" video & text version
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。