最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • San CLI 的实现原理

    正文概述 掘金(百度架构师)   2021-03-12   600

    导读:上期我们讨论了 San CLI 的使用,这期我们再深入一点,来看看 San CLI 的实现原理。

    一、核心模块和核心概念

    为了方便理解下文的 San CLI 的整体工作流程(主流程),我们先来看下 San CLI 的核心模块和核心概念。

    1. 核心模块

    San CLI 的核心模块包括:

    • san-cli:负责 San CLI 的主流程和实现核心功能;

    • san-cli-service:Service 层,负责 Service 流程;

    • san-cli-command-init:实现 san init 命令的 Command 插件

    • san-cli-plugin-*:Service 插件;

    • san-cli-utils:工具库,在插件中也可以直接使用;

    • san-cli-webpack:webpack build 和 dev-server 的通用逻辑,webpack 自研插件等。

    2. 核心概念

    核心概念主要有流程和**插件。**其中,流程又分为主流程和 Service 流程,插件又分为 Command 插件 和 Service 插件:

    • 流程:San CLI 的流程分为两段,主流程和 Service 流程:

    主流程san-cli/index.js 的流程,是整个 San CLI 的工作流程。当我们在命令行输入 San CLI 相关的命令后,比如 san initsan serve(对应 npm start) 和 san build(对应 npm run build),就会进入主流程,主流程会执行对应命令的 handler。有的命令的 handler 不直接包含处理逻辑,而是引入 san-cli-service,比如 san servesan build,输入这类命令时,就会从主流程进入 Service 流程。
    Service 流程san-cli-service/Service.js 的流程,主要处理 Webpack 构建相关的逻辑。

    • 插件:用于扩展 San CLI 的功能:

    Command 插件:用于主流程,执行 Command 插件定义的命令后主流程就会执行对应的 Command 插件的 hanlder
    Service 插件:用于 Service 流程,处理 Webpack 构建相关的逻辑。

    二、整体工作流程

    San CLI 的整体工作流程,即主流程,在 san-cli/index.js 中,大致如下:

    1. 检查 node 版本;

    2. 检查 san-cli 版本;

    3. 调用 san-cli/lib/Commander.js 创建命令实例:

    4. 添加全局 option;

    5. 添加中间件:

    6. 设置全局 logLevel;

    7. 设置 NODE_ENV 环境变量;

    8. argv 添加日志等属性和方法。

    9. 加载内置命令: initservebuildinspectui 等;

    10. 加载 package.jsonsanrc.json 里声明的预置命令(自定义命令);

    11. sanrc.json是配置San CLI的文件,和san.config.js不同,后者是配置项目的文件,详见San CLI官方文档。

    12. 触发命令的 hanlder,开始 San CLI 的正式执行。

    San CLI 的实现原理

    结合核心模块的主流程如下图所示:

    San CLI 的实现原理

    三、san init

    san init命令用于初始化项目,用法在上期已有所介绍,这期我们来看该命令是怎么做到初始化一个项目的。

    1. 流程

    san init初始化项目的原理,简单来说,就是通过 git 命令远程拉取项目脚手架模板的代码库到本地,或者直接使用本地的项目脚手架模板的代码库,然后使用 vinyl-fs 将拉取到的代码库的文件依次处理,处理完成就得到了一个初始化好的项目。

    vinyl-fs是gulp的核心。

    san init主要由四步串行任务组成:

    1. 检查目录和离线包状态:检查项目脚手架模板的本地路径和离线包是否可用;

    2. 下载项目脚手架模板:从 Github 等远程仓库下载项目脚手架模板到模板缓存目录;

    3. 生成项目目录结构:使用 vinyl-fs 把项目脚手架模板从缓存目录遍历处理到开发者指定的项目目录;

    4. 安装项目依赖:询问开发者是否安装 package.json 里的依赖。

    对应的流程图如下图所示:

    San CLI 的实现原理

    其中,检查目录和离线包状态的流程图如下:

    San CLI 的实现原理

    2. 设计思路

    san init的具体实现在san-cli-command-init模块中,san-cli-command-init 模块是一个 Command 插件,其核心是一个TaskList类,san init的执行过程的本质就是:传入上述4个任务组成的数组来实例化TaskList并调用实例的run方法。

    我们来看下 TaskList 的内部实现。

    当调用 TaskList 实例的 run 方法时,首先会对执行实例化 TaskList 时传入的任务列表的第一个任务进行处理。

    因为这些任务本质上都是一个个函数,所以先给第一个任务加上一些方法,比如表示这个任务已完成的 complete 方法,加完方法后,就调用第一个任务函数。

    调用第一个任务函数,就意味着第一个任务开始执行了,当第一个任务该做的事情都做完后,最后就会在这个任务函数中调用之前给这个任务函数加上的 complete 方法。

    complete方法就做一件事情,让 TaskList 实例开始处理下一个任务,处理方式和上面说的一样,只是简单地重复。

    最后, TaskList 实例发现没有下一个任务了,就收工了。

    3. TaskList 源码简化版

    我们用简化版的源码来看下 TaskList 的使用和实现。

    TaskList的使用:

    San CLI 的实现原理

    checkStatus 为例,看下任务函数的实现:

    San CLI 的实现原理

    TaskList 的实现:

    San CLI 的实现原理

    我们可以看出, san init 的设计模式还是比较优秀的,举个栗子,如果我们想给 san init 添加多一个任务,那只需要关注该任务本身的实现,实现好后放入实例化 TaskList 时传入的任务列表中,就可以了,可扩展性非常好。

    四、插件机制

    San CLI 的插件分为 Command 插件和 Service 插件,在上期我们以实际例子讨论了具体怎么开发一个 Command 插件或 Service 插件了,这期我们就来看看 San CLI 的插件机制。

    1. Command 插件

    Command 插件相对 Service 插件来说,机制比较简单。

    Command 插件实际是 yargs 的插件系统的扩展,yargs 是一个 npm 包,用它我们可以定义我们自己的命令行命令。

    回顾下我们在上期创建的 Command 插件:

    San CLI 的实现原理

    之所以要这么写,是因为这是 yargs 对定义一个命令的要求。定义好命令后,就在项目的 package.json 里声明这个命令。

    当我们执行任何一个 san 的命令时——注意,是任何一个——在真正执行这个命令之前,San CLI 会先去读取 package.json 里声明的命令,然后找到命令的定义并传入 yargs,此时,yargs 就知道了都有些什么命令,在此之后,San CLI 才把我们执行的命令的名字和参数传如 yargs,yargs 拿到命令的名字和参数后,就回去执行对应命令的 hanlder。

    Command 插件的机制就是这样。

    另外还值得注意的是,在 san-cli/lib/commander.js 里定义了一个名为 Command 的类,这个类对 yargs 插件做了一些定制,比如通过中间件机制添加了常用的方法和属性到 argv 对象中,方便下游 handler 直接使用。

    2. Service 插件

    San CLI 的 Service 插件机制借鉴了 Vue CLI 的 Service 插件机制,但有一些不同之处:

    • Vue CLI 注册一个新命令是通过 Service 插件来完成的,具体是使用 Service 插件的 registerCommandAPI 方法实现;而 San CLI 把注册一个新命令的逻辑从 Service 插件里分离了出来,成为了一个独立的部分,也就是前面介绍过的 Command 插件。

    • Vue CLI 的一个命令对应一个或多个 Service 插件,也就是说,一个命令的实现由一个或多个 Service 插件来完成;而 San CLI 的一个命令对应零个或所有 Service 插件(引入的),一个命令对应零个的情况是这个命令是一个纯的 Command 插件,一个命令对应所有 Service 插件的情况是这个命令在它对应的 Command 插件的逻辑里触发了 Service 流程,而 Service 流程会依次注册并执行所有的 Service 插件。

    下面我们会以 san serve 命令为例,分别看下 Service 流程、Service 插件的设计思路和 Service 类的简化版源码。

    1)Service 流程

    Service 流程,即 Service 的整个工作流程:

    1. San CLI 在主流程解析输入命令行的 san serve 命令,进入 san-cli/commands/servehandler

    2. san serve 命令的 handler 主要是实例化 Service,实例化会将配置项和 Service 插件进行处理;

    3. 执行 service.run(callback),进入 Service 流程,Service 流程的实现主要在 service.run 中:

    4. loadEnv:加载 env 文件;

    5. loadProjectOptions:加载 san.config.js

    6. init:service 启动:

    7. 初始化插件,即依次执行插件;

    8. 依次执行 webpackChain 回调栈;

    9. 依次执行 webpackConfig 回调栈;

    10. 执行 callback

    对应的流程图如下:

    San CLI 的实现原理

    我们自定义的 Service 插件的具体执行时机是在 3-1-1 “初始化插件,即依次执行插件” 这一步,对应上图中的 “初始化插件(插件.apply)” 这一步。

    上图中的 “初始化 plugin 变量并加载传入的 plugin” 这一步和 “加载 config 中 plugins 里设置的插件” 这一步,其实都是在加载 Service 插件,只不过前者是在加载内置插件和 sanrc.json 里预设的插件,而后者主要是在加载 san.config.json 里的插件。

    加载 Service 插件的流程图如下:

    San CLI 的实现原理

    2)设计思路

    输入 san serve 命令,触发对应的 handlerhandler 主要就做两件事情:一是实例化 Service,二是调用 Service 实例的 run 方法。

    实例化 Service 时,会加载内置 Service 插件和 sanrc.json 里预设的 Service 插件。如果我们自定义的 Service 插件预设在了 sanrc.json 里,比如上期的 san-cli-plugin-get-entry,这个时候就会被加载了。

    实例化完 Service,就调用 Service 实例的 run 方法。

    调用 run 方法时,首先会加载 san.config.js 里的 Service 插件,当然也包括我们放在 san.config.js 里的自定义 Service 插件;然后,该加载的 Service 插件都加载完了,这时就准备依次执行它们了。

    在执行每个 Service 插件之前,会先实例化 PluginAPIPluginAPI 实例给 Service 插件提供了用于处理 Webpack 构建相关逻辑的方法,比如 configWebpack,通过这个方法我们可以在 Service 插件里获取和修改 Webpack 配置,比如在上期我们写的 Service 插件示例里,就用这个方法获取了网站的入口文件名。

    最后,把 PluginAPI 实例作为入参来调用 Service 插件定义的 apply 函数,就正式开始了 Service 插件的执行。

    3)Service 源码简化版

    Service的使用:

    San CLI 的实现原理

    Service 的实现:

    San CLI 的实现原理

    PluginAPI 的实现:

    San CLI 的实现原理

    五、最后

    感谢你阅读到了这里,以上便是《San CLI 的实现原理》的全部内容。如果你都看懂了,请收下我的膝盖:

    San CLI 的实现原理

    2021年,San-CLI还会有持续的开发和优化,比如eject功能、CLI和Service要不要分离,想了解后续的更新,可以关注San CLI的GitHub,欢迎star、欢迎issues、欢迎pr。

    地址:github.com/ecomfe/san-…

    原文链接:mp.weixin.qq.com/s/-yhs_86CA…

    百度架构师

    百度官方技术公众号上线啦!

    技术干货 · 行业资讯 · 线上沙龙 · 行业大会

    招聘信息 · 内推信息 · 技术书籍 · 百度周边

    欢迎各位同学关注!


    起源地下载网 » San CLI 的实现原理

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元