你好,我是轩脉刃。
终于来到框架设计与完善的最后一节课了。在前面的章节中,我们基本上把框架的功能都开发完成了,但是这只是万里长征的第一步。一个工业级的Web框架一定是经过长时间千锤百炼的迭代升级的。在这门课编写完成的时候,我为hade框架锁定了v 1.0.0版本,后续我们会继续为框架增加更多的功能和特性。
那么随着框架的不断更新和升级,随之而来的问题就是如何为一个开源项目设计一套发布和使用机制,并且为每个发布版本维护一套准确的框架说明文档?这就是我们今天要讨论的内容。
每个框架发布都需要有一个版本号,这个版本号如何定义,我们在前面的课程中已经不止一次提到过了,这里再正式说明一下。
所有开源软件的版本号基本上都遵循“语义化版本规范”的约定,这份语义化版本规范是由Gravatars 创办者兼 GitHub 共同创办者 Tom Preston-Werner 所建立的,它定义了三段式的版本规范,格式如下:
主版本号.次版本号.修订号
我们使用的Golang语言项目也是基于这个规范来实现的。
主版本号代表如果做了不兼容的API修改。比如在你的项目中,原先提供的A方法要替换为B方法,所有的参数和返回值都已经变化了,你的使用方必须修改他的代码,这个变动就叫做“不兼容的API修改”。这个时候,主版本号就必须更新了。
次版本号表示当你做了向下兼容的功能性新增。比如原先你的类中只有A方法,当你新增了一个B方法,但是并不修改原先的A方法,这个时候你的类有A、B两个方法。原先的库使用者并不需要更新他的任何代码,这就是“向下兼容的功能性新增”。这个时候,你不需要更新主版本号,只需要更新次版本号就行。
修改号,表示当你做了向下兼容的问题修正。比如原先类中只有A方法,你并没有更新任何的功能,只是修改了A方法中的一个bug,那么这个时候,不需要更新主版本号和次版本号,直接更新修订版本号就行。
这个语义化版本规范,基本上已经是开源届的共识了,当然也可以不遵循这个规范,但是一旦不遵循,对你开源项目的使用者来说绝对是一个灾难性的事情,进而你的项目也逐渐会失去使用者。
我们使用的Go语言版本就是严格遵循这个规范的。比如现在使用的Golang版本为1.17.2。主版本为1,次版本为17,修改号为2。基本上我们接触Golang都是从1.0.0之后开始的,目前Go还没发布2.0.0,所以1.0之后的Go版本升级都是向下兼容的。如果有做过Go升级的同学可以思考下,在升级的时候,业务代码有没有做任何变动。
另外再附带说一下,你也有可能在网络上看到版本号不止三个的,比如1.2.3.4,或者 1.2.3.beta。这些都是对这个语义化规范的扩展使用而已,最后一个字段根据不同的项目可能有不同的意思,比如是否是发行版本。不过前三个版本号都是遵循这个版本规范的。所以见到这些扩展版本号不要吃惊。
我们的hade框架当然也要基于这个版本规范,在这门课程更新完成之后,我会把这门课程的所有代码锁定为一个发布版本1.0.0,并且从这个版本开始继续迭代更新功能。有新的功能和模块增加,我们会升级次版本号,有任何的bug修复,就升级修订版本号。
明确了hade的版本号规范之后,要明确我们的发布模式,这个在前面的第22节课开发自动化脚手架已经简单说过了,这里再正式说明一下。
我们的框架最终在GitHub上的地址为:https://github.com/gohade/hade ,会至少为每一个次版本号打上release版本。
而对于框架的使用者来说,使用步骤会是这样的。首先需要在工作机器上安装hade命令,我们可以在任何路径调用:
go install github.com/gohade/hade@latest
来安装hade命令。这个hade命令,其实用任何版本都是可以的,这里直接选用最新版本。
调用了go install 之后,hade命令就被安装到你的$GOPATH/bin目录下了。直接调用 $GOPATH/bin/hade
可以看到安装好的hade命令。
然后使用 hade new
命令创建一个项目,比如为hellohade。我们可以看到创建出了目标文件夹hellohade。
进入目标文件夹 cd hellohade
,调用 go mod tidy
下载所有的依赖包,调用 go build
编译目录。
接下来,使用者就可以在这个目标文件夹中开始基于hade开发应用了。
到这里,我们把框架的版本和发布的流程梳理清楚了。但是随着版本不断迭代更新,框架对应的说明文档也是需要不断更新的,这就涉及框架文档的编写和搭建了。
对于一个开源项目,说明文档的查看渠道是多种多样的。
对于比较小型的项目和类库,一般都会选择直接使用markdown来编写。比如我们在之前用到的 go-daemon 库,功能比较简单,就是创建一个daemon进程,它的使用方式也比较简单,所以,作者就在项目GitHub地址的 README.md 中写所有信息的使用文档了。
而对于比较大型的项目,大多数项目都会自己开启一个官方网站,来说明项目的各种使用方法,比如gorm 项目,这个库封装的函数多种多样,所以作者单独创建了一个网站来列出对gorm项目的说明。
使用网站来展示项目使用文档有一个额外工作,就是当版本升级的时候,要同时升级官方文档。否则的话,使用者就会经常遇到看旧文档、使用新框架的情况,而导致错误的用法。所以必须及时维护代码和文档的一致性。
那有没有办法将这两者结合一下呢?我们使用markdown编写说明文档,然后如果能自动将这些markdown文档转化为HTML网站,再将网站部署到服务器上,那就完美了。
确实是有这样的工具的,vuepress。vuepress是一个Vue工具,基于Vue框架生成了一个vuepress的命令行工具,这个工具能将指定的markdown文件转化为HTML文件,而这个HTML文件是可以直接被使用者访问的。
vuepress的编译需要两个目录,存放markdown的目录和生成HTML的目标目录。vuepress是基于Vue的,正好hade框架也已经融合了Vue。所以自然可以想到,直接将存放markdown的目录放在hade框架地址上,然后将生成HTML的目标目录定义为我们的dist目录。这样,就可以在hade框架上使用npm工具来生成HTML了。
于是我们在根目录下创建docs目录,存放编写的markdown文件。
这里框架说明的markdown文件我都事先编写完成,也存放在GitHub上了,你可以比对查看。vuepress的markdown文件格式,编写并没有什么特别,只需要你多阅读尝试,心里对哪种格式最终的页面展现是什么样子有理解就行。
比如想要首页的展示形式是这样:
它对应的markdown为dos/README.md:
---
home: true
actionText: 开始体验
actionLink: /guide/introduce
footer: MIT Licensed | Copyright © 2020-present jianfengye
features:
- title: 基于协议
details: 服务与服务间的协议是基于协议进行交互的。
- title: 前后端协同
details: 前后端协同开发
- title: 命令行
details: 有充分的命令行工具
- title: 集成定时服务
details: 如果你需要启动定时服务,提供命令进行定时服务的启动
- title: 文档丰富
details: 提供丰富的文档说明,提供丰富的文档说明
- title: 开发模式
details: 在开发模式下进行前后端开发,极大提高了开发效率和开发体验
根据vuepress的官方文档,我们需要在docs目录下创建一个.vuepress/config.js ,来给vuepress工具阅读,也就是用来告诉vuepress工具,你需要按照这个配置的信息生成HTML文件。这里的所有配置都在官网有说明。
我们的config.js的配置如下:
module.exports = {
title: "hade框架", // 设置网站标题
description: "一个支持前后端开发的基于协议的框架", //描述
dest: "./dist/", // 设置输出目录
port: 2333, //端口
base: "/v1.0/",
head: [["link", {rel: "icon", href: "/assets/img/head.png"}]],
themeConfig: {
//主题配置
// logo: "/assets/img/head.png",
// 添加导航栏
nav: [
{text: "主页", link: "/"}, // 导航条
{text: "使用文档", link: "/guide/"},
{text: "服务提供者", link: "/provider/"},
{
text: "github",
// 这里是下拉列表展现形式。
items: [
{
text: "hade",
link: "https://github.com/gohade/hade",
},
],
},
],
// 为以下路由添加侧边栏
sidebar: {
"/guide/": [
{
title: "指南",
collapsable: false,
children: [
"introduce",
"install",
"build",
"structure",
"app",
"env",
"dev",
"command",
"cron",
"middleware",
"swagger",
"provider",
"todo",
],
},
],
"/provider/": [
{
title: "服务提供者",
collapsable: false,
children: [
"app",
"env",
"config",
"log",
],
},
],
},
},
};
说明下几个重点配置项。
dest这个配置项指定了我们生成HTML的目标文件夹,这里定义为dist目录。base代表所有页面的访问前缀,我们定义为和版本号一致的/v1.0/。这样设置最终会有什么效果呢?
由于hade会有多个版本,而我们希望访问地址的URL中带着版本信息,这样就能通过URL来访问不同的版本信息。比如hade.funaio.cn/v1.0/,访问v1.0的版本信息;hade.funaio.cn/v1.1/ 访问v1.1的版本信息。所以使用/v1.0/的base,能让所有的访问信息都带上这个前缀,就能访问到不同版本的框架信息了。
themeConfig.nav是配置导航栏的,我们的导航栏有四个信息。
所以在themeConfig.nav中需要定义四个子项,子项目的text表示显示文本,而link表示点击这个文本之后的链接地址。比如:
{text: "使用文档", link: "/guide/"},
表示“使用文档”这个文本点击之后,会查找/guide/目录下的README文件。
而/guide/目录下的所有文件是通过themeConfig.sidebar设置侧边栏的,也就是刚才代码的第29到47行。最终通过这段的设置,点击首页的“使用文档”链接,就会进入如下的效果:
左边的每个链接都对应docs/guide/中的每个markdown文件。
docs下的markdown文件都编写完成了,下面我们就安装vuepress并且生成HTML。安装vuepress,只需要使用npm命令:
npm install -D vuepress
就能安装最新版本的vuepress。截止11月13日,目前vuepress的2.0还处在beta版本,最稳定版本是1.8.2。在安装过程中你可能会遇到这个错误:
TypeError: Cannot read property 'createHash' of undefined
这个错误是提示我们的Webpack版本较低,使用命令升级Webpack就行。
npm i webpack@4.8.3
安装好vuepress之后,我们就可以在package.json中设置vuepress的调试和编译命令了:
{
"name": "hade",
...
"scripts": {
...
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
增加了docs:dev 和 docs:build 来运行vuepress。
这里我们使用 npm run docs:build
,就能生成对应markdown的HTML了,非常方便。
可以看到dist目录中已经生成了对应的HTML文件:
最后将这个HTML文件部署到Web服务器中。这里我们部署在目标服务器的的/webroot/hade_doc/dist_1.0目录中。具体部署方法也没有什么难点,通过FTP或者SETP上传dist目录内容到目标目录即可。
我们的目标服务器配置的Web服务器为Nginx,Nginx如何配置,你可以参考:
server {
server_name hade.funaio.cn;
access_log logs/hade.access.log main;
error_log logs/hade.error.log ;
location /v1.0/ {
alias /webroot/hade_doc/dist_1.0/;
index index.html index.htm;
}
location / {
root /webroot/hade_doc/dist_1.0/;
index index.html index.htm;
}
}
配置hade.funaio.cn/v1.0/ 来访问目录路径 /webroot/hade_doc/dist_1.0/ ,同时hade.funaio.cn/也是访问/webroot/hade_doc/dist_1.0/。
这样每次我们的版本有更新的时候,创建一个新的目标目录存放这个版本的HTML,比如 /webroot/hade_doc/dist_1.1/。而在nginx上,只需要增加一个路径/v1.1/来提供hade.funaio.cn/v1.1/的访问路径,让使用者访问v1.1的文档。
于是,我们hade框架的网站文档:http://hade.funaio.cn 就正式搭建起来了。
看到这里,相信你应该理解了,我们的文档维护是基于hade项目中自带的docs/ 目录下的markdown 来进行的。你可以通过GitHub上的markdown 来查看框架文档,也可以通过网站 hade.funaio.cn 来查看框架文档。这两者本质上都是通过markdown来编写的。
而markdown会随着hade框架的发布而发布,同时网站也是根据markdown生成的。这种方法既能避免文档和框架不一致的问题,又能大大降低维护网站的成本。
这节课我们没有修改框架的Go代码,主要创建了包含markdown文件的docs目录。目录截图放在这里供你你参考。所有代码也同步到了geekbang/29 分支上了。
今天我们为框架的升级和维护设计了一套完整的方案。hade框架的发布和文档维护都有自己的独特设计,比如框架的发布,直接和hade框架的命令行工具进行了关联,只要发布了一个新版本,使用者就能直接用命令行工具使用这个新版本创建一个脚手架。而文档维护,是通过编写markdown以及hade框架已经集成的Vue,来自动生成网站HTML。
截止到这节课,hade框架的功能就开发完毕了,GitHub上的coredemo项目也就不再更新了,之前的所有代码,我们都会移动到真正的hade项目的 https://github.com/gohade/hade 地址,并且我们为代码发布了发布版本:v1.0.0,后续会基于这个版本不断迭代更新,如果你有兴趣,欢迎一起来完善这个框架。
马上我们会进入实战环节,使用hade框架开发具体应用,会使用到Vue和Element-UI的知识,当然在后面我们也会稍微介绍一些前端知识,不过如果你之前完全没有接触过,可以花一些时间预习一下,这样学习的时候才能事半功倍。
所以今天就给你分享一些相关资料:
欢迎在留言区分享你的学习笔记。感谢你的收听,如果你觉得今天的内容对你有所帮助,也欢迎分享给你身边的朋友,邀请他一起学习。我们实战篇见。