You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
18 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 29周边框架发布和维护也是重要的一环
你好,我是轩脉刃。
终于来到框架设计与完善的最后一节课了。在前面的章节中我们基本上把框架的功能都开发完成了但是这只是万里长征的第一步。一个工业级的Web框架一定是经过长时间千锤百炼的迭代升级的。在这门课编写完成的时候我为hade框架锁定了v 1.0.0版本,后续我们会继续为框架增加更多的功能和特性。
那么随着框架的不断更新和升级,随之而来的问题就是如何为一个开源项目设计一套发布和使用机制,并且为每个发布版本维护一套准确的框架说明文档?这就是我们今天要讨论的内容。
### 版本
每个框架发布都需要有一个版本号,这个版本号如何定义,我们在前面的课程中已经不止一次提到过了,这里再正式说明一下。
所有开源软件的版本号基本上都遵循“[语义化版本规范](https://semver.org/lang/zh-CN)”的约定这份语义化版本规范是由Gravatars 创办者兼 GitHub 共同创办者 Tom Preston-Werner 所建立的它定义了三段式的版本规范格式如下
```plain
主版本号.次版本号.修订号
```
我们使用的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节课](https://time.geekbang.org/column/article/435534)开发自动化脚手架已经简单说过了,这里再正式说明一下。
我们的框架最终在GitHub上的地址为[https://github.com/gohade/hade](https://github.com/gohade/hade) 会至少为每一个次版本号打上release版本。
![](https://static001.geekbang.org/resource/image/ca/75/caec1bcef876ba937a5eacf036e58975.png?wh=1920x1025)
而对于框架的使用者来说使用步骤会是这样的。首先需要在工作机器上安装hade命令我们可以在任何路径调用
```go
go install github.com/gohade/hade@latest
```
来安装hade命令。这个hade命令其实用任何版本都是可以的这里直接选用最新版本。
调用了go install 之后hade命令就被安装到你的$GOPATH/bin目录下了。直接调用 `$GOPATH/bin/hade` 可以看到安装好的hade命令。
![](https://static001.geekbang.org/resource/image/b8/c0/b8eec8f059ac82a5a5f1de6657dba7c0.png?wh=1920x1172)
然后使用 `hade new` 命令创建一个项目比如为hellohade。我们可以看到创建出了目标文件夹hellohade。
![](https://static001.geekbang.org/resource/image/c4/fc/c4de7585ff0c36e79ef038bcdf952bfc.png?wh=1920x1312)
进入目标文件夹 `cd hellohade` ,调用 `go mod tidy` 下载所有的依赖包,调用 `go build` 编译目录。
![](https://static001.geekbang.org/resource/image/03/92/030ec01edf75260c35782db1413ed192.png?wh=1566x1044)
接下来使用者就可以在这个目标文件夹中开始基于hade开发应用了。
![](https://static001.geekbang.org/resource/image/ea/8e/ea74acc44f15623d50dd4608e1cyy48e.png?wh=1920x1320)
## 文档维护
到这里,我们把框架的版本和发布的流程梳理清楚了。但是随着版本不断迭代更新,框架对应的说明文档也是需要不断更新的,这就涉及框架文档的编写和搭建了。
对于一个开源项目,说明文档的查看渠道是多种多样的。
对于比较小型的项目和类库一般都会选择直接使用markdown来编写。比如我们在之前用到的 [go-daemon](https://github.com/sevlyar/go-daemon) 库功能比较简单就是创建一个daemon进程它的使用方式也比较简单所以作者就在项目GitHub地址的 README.md 中写所有信息的使用文档了。
而对于比较大型的项目,大多数项目都会自己开启一个官方网站,来说明项目的各种使用方法,比如[gorm](https://github.com/go-gorm/gorm) 项目,这个库封装的函数多种多样,所以作者单独创建了一个[网站](https://gorm.io/zh_CN/docs/index.html)来列出对gorm项目的说明。
使用网站来展示项目使用文档有一个额外工作,就是当版本升级的时候,要同时升级官方文档。否则的话,使用者就会经常遇到看旧文档、使用新框架的情况,而导致错误的用法。所以必须及时维护代码和文档的一致性。
那有没有办法将这两者结合一下呢我们使用markdown编写说明文档然后如果能自动将这些markdown文档转化为HTML网站再将网站部署到服务器上那就完美了。
确实是有这样的工具的,[vuepress](https://vuepress.vuejs.org/zh/guide)。vuepress是一个Vue工具基于Vue框架生成了一个vuepress的命令行工具这个工具能将指定的markdown文件转化为HTML文件而这个HTML文件是可以直接被使用者访问的。
**vuepress的编译需要两个目录存放markdown的目录和生成HTML的目标目录**。vuepress是基于Vue的正好hade框架也已经融合了Vue。所以自然可以想到直接将存放markdown的目录放在hade框架地址上然后将生成HTML的目标目录定义为我们的dist目录。这样就可以在hade框架上使用npm工具来生成HTML了。
## 编写markdown
于是我们在根目录下创建docs目录存放编写的markdown文件。
这里框架说明的markdown文件我都事先编写完成也存放在GitHub上了你可以比对查看。vuepress的markdown文件格式编写并没有什么特别只需要你多阅读尝试心里对哪种格式最终的页面展现是什么样子有理解就行。
比如想要首页的展示形式是这样:
![](https://static001.geekbang.org/resource/image/ca/2f/cae7c6eb3fc8971f5e4534538e78232f.png?wh=1920x589)
它对应的markdown为dos/README.md
```markdown
---
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文件。这里的所有配置都在[官网](https://vuepress.vuejs.org/zh/config)有说明。
我们的config.js的配置如下
```javascript
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是配置导航栏的我们的导航栏有四个信息。
![](https://static001.geekbang.org/resource/image/f7/59/f72cd0a32e3d76bf5b67798dbe495e59.png?wh=318x52)
所以在themeConfig.nav中需要定义四个子项子项目的text表示显示文本而link表示点击这个文本之后的链接地址。比如
```javascript
{text: "使用文档", link: "/guide/"},
```
表示“使用文档”这个文本点击之后,会查找/guide/目录下的README文件。
而/guide/目录下的所有文件是通过themeConfig.sidebar设置侧边栏的也就是刚才代码的第29到47行。最终通过这段的设置点击首页的“使用文档”链接就会进入如下的效果
![](https://static001.geekbang.org/resource/image/c7/16/c72c2edcdc7f4ed9abe098a3285ae016.png?wh=1308x638)
左边的每个链接都对应docs/guide/中的每个markdown文件。
### 生成HTML
docs下的markdown文件都编写完成了下面我们就安装vuepress并且生成HTML。安装vuepress只需要使用npm命令
```go
npm install -D vuepress
```
就能安装最新版本的vuepress。截止11月13日目前vuepress的2.0还处在beta版本最稳定版本是1.8.2。在安装过程中你可能会遇到这个错误:
```plain
TypeError: Cannot read property 'createHash' of undefined
```
这个错误是提示我们的Webpack版本较低使用命令升级Webpack就行。
```plain
npm i webpack@4.8.3
```
安装好vuepress之后我们就可以在package.json中设置vuepress的调试和编译命令了
```go
{
"name": "hade",
...
"scripts": {
...
"docs:dev": "vuepress dev docs",
"docs:build": "vuepress build docs"
},
```
增加了docs:dev 和 docs:build 来运行vuepress。
这里我们使用 `npm run docs:build` 就能生成对应markdown的HTML了非常方便。
![](https://static001.geekbang.org/resource/image/85/37/85a2882ca4500282f43d23110fc07537.png?wh=698x518)
可以看到dist目录中已经生成了对应的HTML文件
![](https://static001.geekbang.org/resource/image/f0/9b/f0671ba855661eb73fb4c4a49f65ed9b.png?wh=321x168)
最后将这个HTML文件部署到Web服务器中。这里我们部署在目标服务器的的/webroot/hade\_doc/dist\_1.0目录中。具体部署方法也没有什么难点通过FTP或者SETP上传dist目录内容到目标目录即可。
我们的目标服务器配置的Web服务器为NginxNginx如何配置你可以参考
```plain
    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](http://hade.funaio.cn) 就正式搭建起来了。
![](https://static001.geekbang.org/resource/image/c2/6c/c235a8ce622fdfa33e6dc382bfac566c.png?wh=1920x855)
看到这里相信你应该理解了我们的文档维护是基于hade项目中自带的docs/ 目录下的markdown 来进行的。你可以通过GitHub上的[markdown](https://github.com/gohade/coredemo/blob/geekbang/29/README.md) 来查看框架文档,也可以通过网站 hade.funaio.cn 来查看框架文档。这两者本质上都是通过markdown来编写的。
而markdown会随着hade框架的发布而发布同时网站也是根据markdown生成的。这种方法既能避免文档和框架不一致的问题又能大大降低维护网站的成本。
这节课我们没有修改框架的Go代码主要创建了包含markdown文件的docs目录。目录截图放在这里供你你参考。所有代码也同步到了[geekbang/29](https://github.com/gohade/coredemo/tree/geekbang/29) 分支上了。
![](https://static001.geekbang.org/resource/image/c0/25/c0c15e07407e6a7102913446ed46b725.png?wh=361x670)
## 小结
今天我们为框架的升级和维护设计了一套完整的方案。hade框架的发布和文档维护都有自己的独特设计比如框架的发布直接和hade框架的命令行工具进行了关联只要发布了一个新版本使用者就能直接用命令行工具使用这个新版本创建一个脚手架。而文档维护是通过编写markdown以及hade框架已经集成的Vue来自动生成网站HTML。
截止到这节课hade框架的功能就开发完毕了GitHub上的coredemo项目也就不再更新了之前的所有代码我们都会移动到真正的hade项目的 [https://github.com/gohade/hade](https://github.com/gohade/hade) 地址并且我们为代码发布了发布版本v1.0.0,后续会基于这个版本不断迭代更新,如果你有兴趣,欢迎一起来完善这个框架。
### 思考题
马上我们会进入实战环节使用hade框架开发具体应用会使用到Vue和Element-UI的知识当然在后面我们也会稍微介绍一些前端知识不过如果你之前完全没有接触过可以花一些时间预习一下这样学习的时候才能事半功倍。
所以今天就给你分享一些相关资料:
* [vue中文官网](https://cn.vuejs.org/index.html)学习Vue必看内容
* [element-ui官网](https://element.eleme.io/#/zh-CN)一款快速搭建网站的UI框架目前国内最火
* [awesome-vue](https://github.com/rumengkai/awesome-vue)收集Vue的一些优秀开源项目绝对收藏
* [vue router官网](https://router.vuejs.org/zh)Vue的路由必备
* [webpack官网](https://v4.webpack.docschina.org/concepts)Vue的打包工具
欢迎在留言区分享你的学习笔记。感谢你的收听,如果你觉得今天的内容对你有所帮助,也欢迎分享给你身边的朋友,邀请他一起学习。我们实战篇见。