Docsify+GithubPages建站踩坑攻略

布景

上一年年度述职,我感觉构建自己的研发管理知识系统比较重要,然后想挑选一款免费的管理自己的WIKI的东西

之前用过hugo布置过静态博客,可是这个比较合适单篇的博客,感觉不合适系统化的记录知识,

后边又想到了gitbook,可是其主题太单调了,终究发现了docsify,比较干净清新,颜值尚可,终究就决议运用这个东西记录我的个人系统化WIKI

其实东西是非必须的,最主要的仍是自己要不断地输出内容。

docsify运用+github pages布置

跟着官网的教程根本上能够完结建站加布置

可是有个问题,假如想要使得 https://xxx.github.io/ 翻开便是该网站主页

那么文章需求放在xxx.github.io库房下面,假如是在其他库房B,那么得https://xxx.github.io/B/ 才是该站点的主页

踩过的坑

根底运用上,跟着官方的教程走不会出问题,在插件的运用上,仍是需求一些踩坑经验的,我现在主要在运用gitalk时遇到了问题,这里记录一下

0.简略介绍下运用

装备项如下:

clientID: 'Github Application Client ID',
clientSecret: 'Github Application Client Secret',
repo: 'Github repo',
owner: 'Github repo owner',
admin: ['Github repo collaborators, only these guys can initialize github issues'],
distractionFreeMode: false

直接按我的库房来举例说明 https://github.com/noobcoderr/noobcoderr.github.io

clientID和clientSecret生成办法

  • github里点击个人头像进入settings,然后进入Developer settings, 进入Oauth APPs,点击New OAuth App新建一个Oauth运用
  • APPlication Name随意填,Homepage UrlAuthorization callback URL都填https://noobcoderr.github.io/. 此处假如有个人域名,那么Authorization callback URL填个人域名
  • 完结之后会生成一份Client IDClient secrets,secrets初次是完好显示的,需求记录好,后续翻开这个页面就不会显示完好的了,只能新建一个

repo、owner、admin、distractionFreeMode的填写

  • repo便是填库房名,这里对应我的noobcoderr.github.io
  • owner就填用户名,这里对应我的noobcoderr
  • admin也是填用户名或许安排名,便是允许建立issue的人或许安排,这里是个人库房,所以也只填['noobcoderr']
  • distractionFreeMode 无搅扰形式,默认跟着填false

1.谈论紊乱

现象

1、翻开网站后恣意点开一篇文章,进行谈论,然后点开另一篇文章,此刻谈论区坚持和上一篇文章的共同

2、此刻在该文章下进行谈论,此刻检查长途库房issue,发现谈论依然在上一篇issue里

原因剖析

在开发者形式观察Network形式下履行第一步和第二步,发现 改写当时页面时,会履行三次网络恳求

  1. 拜访https://api.github.com/user获取当时github用户信息
  2. 拜访以页面标题为titleGitalk和路由pathlabel为查询条件,查询符合条件的issue信息,此刻为准确查询
  3. 恳求/graphql接口获取issueissue的谈论信息,查询条件为第二步回来的issue_id

Docsify+GithubPages建立个人知识Wiki及Gitalk踩坑指南

当点击一篇其他文章的时分,也会履行上述的三次网络恳求

  1. 拜访https://api.github.com/user获取当时github用户信息
  2. 以初次进入页面时的查询条件查询符合条件的issue
  3. 恳求/graphql接口获取issueissue的谈论信息,查询条件为第二步回来的issue列表里的第一条issueissue_id

能够发现,我们进入网站后点击其他文章时的查询issue条件其实是第一次改写页面时的查询条件,所以后边不论是查询issue下的谈论,仍是对该文章进行谈论, 终究都会限定在符合第一次查询时的issue里。

当然最底层的原因猜测或许切换文章时gitalk组件的生命周期未完毕,依然维护的最开端的一篇文章的挑选条件,切换文字时未运用最新的path作为挑选条件 这个需求剖析其源码或许才能具体定位了。

解决办法

切到一篇文章后假如要进行谈论,改写一下当时页面即可,完毕上一次页面的gitalk的生命周期

2.gitalk模块调整不出来

官方的装备是这样的:

<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.css">
<script src="//cdn.jsdelivr.net/npm/docsify/lib/plugins/gitalk.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/gitalk/dist/gitalk.min.js"></script>
<script>
  const gitalk = new Gitalk({...})
</script>

看了教程以为css和js都放<head>里,或许都放<body>里,可是我当时怎么调终究都没有呈现Gitalk模块

这块官方教程里css文件和js文件中间用一个空行隔开,应该便是css文件引证要放<head>里,js引证要放<body>里,

我前端根底知识较少,所以这块也花了段时间来调整,才把谈论模块调出来。

3.issue初始化创立失败

现象

本地调试时,无法创立issue,在gitalk处点击登录github时,直接回到主页

剖析

这是由于这一步需求运用github登录,会拉起Oauth授权,即你授权给noobcoderr的谈论Oauth运用,拉起授权时需求提供一个redirect url

由所以在本地调试,所以域名为localhost:3000,这个在github授权完结后进行重定向跳转的时分由于不是公网域名,所以无法辨认。

解决办法

所以在本地就不要调试Gitalk了,推到长途分支后,在自己的github-pages页面进行调试

4.部分文章创立的issue都相同

剖析

由于参照docsify官网的装备,没有装备id选项,此刻默认运用的为location.href作为创立issuelabel,便是页面的完好url,

可是githublabel的长度有50的约束,超越50的部分会被截取,只取前50位

而我的域名https://noobcoderr.github.io/#/就已经占有了31的长度了,而我对不同文章的文件夹的命名又比较长

例如编程语言Python下的最佳实践文章,其完好url为https://noobcoderr.github.io/#/ProgramLanguages/Python/python_best_practice,其长度为75

当截取为50长度时的结果为https://noobcoderr.github.io/#/ProgramLanguages/Py,那么Python文件夹下的一切文章的issue都是相同的,由于label超长了,都被截取了 只保存相同的前缀。

解决办法

我看网上有人引荐以下两种,可是通过我的实践,好像都不太行

  • 运用md5(location.href), 这样其实也能够,根据完好url的散列值根本不会重复,便是库房里的labels不直观,由于散列值就仅仅一些随机字符串

  • 运用location.pathname,其实这不合适docsify建立的项目,由于其生成的文章url为host/#/path中间带一个#,取location.pathname取到的便是一个/,那么一切文章的label都相同了 可是运用hugo之类建立的文章好像就没有这个问题,能够运用该值。

通过我的测试,终究运用location.href.split('#')[1]作为id装备项,能够取到正常的pathname,也能够作为页面的唯一标识

Gitalk的源码简略剖析

作为一个Python服务端,看了看Gitalk的源码,仍是能够看出一些表面的意思的,源码文件为gitalk.jsx

关键的一些源码粘贴如下:

class GitalkComponent extends Component {
  state = {
    user: null,
    issue: null,
    comments: [],
    localComments: [],
    comment: '',
    isNoInit: false,
    isIniting: true,
    isCreating: false,
    isOccurError: false,
    errorMsg: '',
  }
  constructor (props) {
    super(props)
    this.options = Object.assign({}, {
      id: window.location.href,
      number: -1,
      labels: ['Gitalk'],
      title: window.document.title,
      body: '', // window.location.href + header.meta[description]
      url: window.location.href,
    }, props.options)
  }
}
  render () {
    const { isIniting, isNoInit, isOccurError, errorMsg, isInputFocused } = this.state
    return (
      <div className={`gt-container${isInputFocused ? ' gt-input-focused' : ''}`}>
        {isIniting && this.initing()}
        {!isIniting && (isNoInit ? [] : [this.meta()])}
        {isOccurError && <div className="gt-error">{errorMsg}</div>}
        {!isIniting && (isNoInit ? [this.noInit()] : [this.header(),this.comments()])}
      </div>
    )
  }
}
module.exports = GitalkComponent

剖析gitalk源码 入口应该为render() 该办法会回来一个gitalkgt-container容器,这个容器便是包含gitalk的模块,履行流程为

  • <第一块> 展现初始化状态,初始化时展现Gitalk 加载中 …
  • <第二块> 在初始化完毕的情况下,假如成功则履行this.meta(), 该部分获取各种元数据并展现
  • <第三块> 在发生错误的时分在gt-error模块内展现错误信息
  • <第四块> 在初始化完毕的情况下,假如成功则履行header办法和comments办法,不成功则履行this.noInit办法

meta办法

只做数据展现,不做数据获取,登录时展现谈论数量,以及一些弹出式菜单,如注销,按时间正序/倒序排序,gitalk版本等等,未登录时展现登录按钮等

header和comments办法

展现已有的数据,没有获取数据操作

noInit办法

该办法这个办法会拿到文章对应issue的一切谈论

  • 最开端是展现未找到相关的issue进行谈论,请联络用户进行创立
  • 假如未登录github的话,展现按钮进行登录,进行Oauth授权,获取用户信息
  • 假如当时登录github用户是此库房管理员的话,那么展现创立issue按钮,调用handleIssueCreate办法
    • handleIssueCreate办法: 会调用createIssue办法创立issue,创立完结后,会调用getComments办法获取当时issue的一切谈论
    • createIssue办法: 创立issue。在装备的owner用户下的repo库房里,以页面的title为issue的标题,以Gitalk和id为issue的labels,以页面完好的url作为issue的内容,即首条谈论
    • getComments办法:获取issue的一切谈论,假如未登录,则调用getCommentsV3办法,假如登录了,则调用graphql的getComments办法
    • getCommentsV3办法:获取issue的谈论,首要按照issue_id进行取,假如取到就展现到页面上,假如未取到则安labels进行取
    • graphql的getComments办法:获取指定issue_id的一切谈论
    • handleLogin办法:会将一切谈论放在浏览器的本地存储里

从源码可见GitalkComponent维护了很多数据,每次进入新页面都会调用render()办法,可是上一次的数据有没有被整理我不太清楚,理论上应该会被整理, 可是上面说到的谈论紊乱确实是感觉有缓存,这点需求后边咨询一下搞前端的同事确认下。

学习到的javascript知识

  • 三元表达式 bool ? A : B ,假如bool为真,则履行A,bool为假,则履行B
  • && 高级用法:用于履行句子 bool && func(), 假如bool为真,则履行后边的句子
  • .jsx文件为React结构对javascript的扩展