Hugo

komantao 2019-12-11 2020-03-09 字数 47981 阅读量 4781


Hugo是使用go(又称golang)语言编写的一个静态网站生成器,主要用于构建Blog、项目文档、静态网站等。以其极快的速度、强大的内容管理和强大模板语言而著称,不仅解决了环境依赖、性能较差的问题,还有简单、易用、高效、易扩展、快速部署等诸多优点,开发过程中使用LiveReload(即时渲染,即时预览网站效果),极大优化了文章写作体验。

“ 静态”的含义反映在网站页面的生成时间。一般web服务器(WordPress、Ghost、Drupal等)在收到页面请求时,需要调用数据库生成页面,再返回给用户请求。静态网站在建立网站前就生成所有页面(称为静态文件),访问时直接返回现成的静态页面,不需要数据库参与。

一、概述

静态网站基本不需要维护,不需要考虑复杂的运行时间、依赖、数据库和安全性等问题。静态网站最大好处是访问快速。当网站有更改时,静态网站生成器需要重新生成所有与更改相关的页面。对于小型的个人网站、项目主页等,网站规模很小,重新生成整个网站也非常快。Hugo在速度方面做得非常好,官方宣传每篇页面的生成时间不到1ms。

如果说速度快是Hugo的第一大优点,那么安装简单应该就是Hugo的第二大优点。

Hexo基于node.js开发,需要依赖环境才能运行,要实现一些主题额外功能还需要下载和匹配各种依赖,甚是麻烦。Hugo基于go开发,打包成独立文件,不需要额外环境,安装并设置系统的环境变量后,就能直接运行,可以说是非常便利和快捷。

1、安装

示例:Windows平台安装Hugo。

  1. Hugo Releases下载对应平台的Hugo二进制文件

    image-20191127114555468

  2. 本地创建一个目录存储Hugo的可执行文件和项目文件

    在本地创建一个新目录:示例为E:/Hugo

    • Hugo目录中创建一个子目录(E:/Hugo/bin):存储可执行文件
    • Hugo目录中创建另一个子目录(E:/Hugo/sites):存储Hugo项目文件
  3. 下载的zip包解压到E:/Hugo/bin文件夹内,就完成了安装

  4. 设置环境变量,将E:/Hugo/bin添加到系统变量中的环境变量Path中

  5. 安装好后,运行hugo version检测是否成功返回版本号

    • $ hugo version
    • Hugo Static Site Generator v0.61.0-9B445B9D windows/amd64 BuildDate: 2019-12-11T08:29:13Z

升级时:将新版本的zip包解压覆盖E:/Hugo/bin文件夹内的文件。

2、命令

语法:

  • hugo [command] [flags]

command的参数(可使用hugo --help命令查看其详细帮助文档)有:

command 功能
config 输出(显示)站点配置
convert 转换内容(content)的格式
deploy 将站点部署到云提供商
env 输出(显示)Hugo版本和环境信息
gen 几个有用的生成器的集合
help 关于任何命令的帮助
import 从其他站点导入您的站点
list 列出内容的各种类型
mod Hugo模块助手
new 为您的站点创建新内容
server 一个高性能的网络服务器(调用本地web服务器)
version 输出(显示)Hugo的版本号

2.1 创建内容文件

在项目根目录(又称网站根目录,示例为Hugo/sites/ebook)中运行Hugo命令。

  • 新建网站(Hugo项目)或主题

    • hugo new [command]

    参数:

    command 功能 示例 备注
    site 新建项目 hugo new site ebook 项目以目录形式存在,目录名任意
    theme 新建主题
  • 网站内新建内容(称为页面文件)

    • hugo new [path] [flags]

    根据提供的路径(path参数)创建一个新的内容文件,根据原型文件自动设置日期和标题等。原型文件使用“-k|–kind”参数指定或由Hugo智能猜测。

    参数 描述 示例 备注
    path 内容文件在content目录中的相对路径 hugo new hugo/hugo.md 文件路径:content/hugo/hugo.md
    flags 使用“-k|–kind”指定内容文件的类型 hugo new --kind chapter hugo/_index.md 文件类型指定为chapter

2.2 编译内容文件

  • 本地预览

    编译生成缓存的静态文件(不会输出到public目录)并启动本地web服务:

    • $ hugo server
    • Building sites …
    • …………
    • Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
    • Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
    • Press Ctrl+C to stop

    一直保持运行命令。手动结束命令后,将会清除缓存的静态文件。

  • 生成网站文件

    生成静态文件并输出到默认的public目录(不会启动本地web服务):

    • $ hugo
    • Building sites …
    • | EN
    • +------------------+-----+
    • Pages | 47
    • Paginator pages | 0
    • Non-page files | 47
    • Static files | 211
    • Processed images | 0
    • Aliases | 11
    • Sitemaps | 1
    • Cleaned | 0
    • Total in 897 ms

3、项目

3.1 、新建项目

CLI(命令行工具,例如cmd、PowerShell或Bash等)进入E:/Hugo/sites目录:

  • E:\>cd E:\Hugo\sites
  • E:\Hugo\sites>

E:/Hugo/sites目录下新建项目(假设名称为ebook):

  • $ hugo new site ebook
  • Congratulations! Your new Hugo site is created in E:\Hugo\sites\ebook.
  • Just a few more steps and you're ready to go:
  • 1. Download a theme into the same-named folder.
  • Choose a theme from https://themes.gohugo.io/ or
  • create your own with the "hugo new theme <THEMENAME>" command.
  • 2. Perhaps you want to add some content. You can add single files
  • with "hugo new <SECTIONNAME>\<FILENAME>.<FORMAT>".
  • 3. Start the built-in live server via "hugo server".
  • Visit https://gohugo.io/ for quickstart guide and full documentation.
  • 提示信息:下载主题、添加内容、运行hugo server命令
  • Hugo没有预设主题,安装Hugo后需要下载主题

3.2 、项目结构

项目目录的树结构为:

  • . # Hugo项目根目录(示例为E:\Hugo\sites\ebook)
  • ├─archetypes # markdown文件的模板,通常用来自定义设置扉页等
  • | └─default.md # 缺省,Hugo预设的一个模板
  • ├─content # 内容目录,存放网站内所有内容文件的源代码
  • | ├─_index.md # 网站的主页(网站的简介)
  • | ├─章节文件夹 # 章节目录,内容文件分类存放
  • | | ├─_index.md # 章节的主页(章节的简介)
  • | | ├─内容文件夹 # 章节内的子页面目录(根据需要设置)
  • | | ├─xxx.md # 子页面内容,通常是markdown文件
  • | | └─本地图片 # markdown文件引用的图片
  • ├─data # 网站的自定义配置文件,文件类型可以是yaml|toml|json等格式
  • ├─layouts # 布局目录,存放渲染content目录的模版文件,模版的文件类型是html格式
  • ├─resource # 主题产生的目录,未明用途
  • ├─static # 静态资源目录,存放静态资源文件,例如:图片、css、js等
  • ├─themes # 主题目录,存放Hugo主题
  • | └─XXX主题 # 安装后的主题名称
  • | | └─layouts # 某个主题下的网站模板文件
  • ├─public # 编译后生成的网站文件
  • └─config.toml # 网站的配置文件(支持格式有:toml、yaml、json)
  • content目录:存放网站内所有页面文件的源代码
  • data目录:存放网站的自定义配置文件
  • static目录:存放源代码的静态资源文件(图片、css、js等)。渲染时,会直接将static目录的文件直接复制到public目录,不做任何渲染
  • 指定主题:在config.toml中使用theme = "xxx"设置默认主题(xxx是theme目录内的主题名), 或运行hugo|hugo server --theme=xxx命令时设置临时渲染主题
  • 优先级:若存在同名文件,Hugo优先使用项目根目录内的文件,然后才是themes目录内的指定主题

4、Hugo的坑

虽然只是一些小问题,但每次重复发生,也是一个麻烦。

  1. Hugo的Date属性带有时区

    Hugo日期格式:date: 2019-12-11T23:19:14+08:00;Hexo日期格式:date: 2019-11-25 18:49:20。在迁移时注意此问题并进行格式转换。

  2. Hugo的网址链接

    若直接输入网址(示例:https://gohugo.io/),Hugo不能识别为网址;

    若粗体显示网址(示例:https://gohugo.io/),Hugo能识别为网址。

  3. Hugo默认使用“Pretty URLs”(漂亮URL),Hexo使用“Ugly URLs”(丑陋URL)

    • ├─content # 网站源代码目录
    • | ├─_index.md # URL转换为:https://example.com/
    • | ├─posts # 一个名为posts的章节文件夹
    • | | ├─_index.md # URL转换为:https://example.com/posts/
    • | | ├─first.md # URL转换为:https://example.com/posts/first/
    • | | └─topic # 章节内的子页面内容目录(包含md文件和图片)
    • | | | ├─second.md # URL转换为:https://example.com/posts/topic/second/
    • | | | └─123.jpg # second.md文件引用的本地图片

    “_index.md”和”index.md”文件在Hugo中具有特殊含义(用于组织页面)。在“Pretty URLs”渲染下,与实际路径一致。

    若文件名不为“_index.md”或“index.md”时,“Pretty URLs”将md文件渲染为目录。导致后果:md文件引用本地图片时,渲染路径比实际路径多了一个与文件名同名的目录名,导致引用图片失败。

  4. Hugo_v0.60的Markdown渲染引擎使用Goldmark,Typora使用GFM’s spec

    1. 代码(<code>标签)/代码块(<pre>标签)内包含html或js语法时

      • Typora

        Typora内的代码块会屏蔽所有语法,只显示源代码。

      • Hugo(Goldmark)

        config.toml中若设置了unsafe = true,将会允许md文件使用html和js语法,执行html或js语句的优先级高于代码块,结果执行代码块内的html语句,导致格式错乱。因此,必须慎重开启unsafe。

    2. 在列表项中新建块/段落时

      Typora成功(参阅严格模式,使用Enter键代替输入空格),Hugo有时失败。

      • 原因一:Hugo的config.toml开启了unsafe = true

      • 原因二:列表项中有代码块(<pre>标签)

        Hugo有时渲染成功,有时渲染失败,暂未明原因。

        解决方法:貌似只要一次性完成列表项就能成功,即不要在现有列表项中插入新的块/段落。若需插入,应该是重写列表项内的所有内容。

      • 原因三:列表项中的代码块的扉页语法貌似不能使用yaml语法

        在md文件的扉页使用了yaml语法的前提下:

        • 若在列表项中的代码块的扉页语法同样使用yaml语法,会造成格式错乱,解决方法是改用toml语法
        • 若代码块不在列表项中时,扉页语法可正常使用yaml语法
    3. 标题锚点的语法

      • Typora

        只能实现页面内跳转(简捷语法:<a href="#标题路径">xx</a>)、页面跳转(Markdown语法:[替换文本](文件相对路径))。

      • Hugo

        Hugo生成的每一个html文件和html文件内的每一个标题在网络上都有唯一的URL,可实现页面内(简捷语法:<a href="#标题网址">xx</a>)、页面、页面间跳转,建议统一使用Markdown语法:[替换文本](标题网址))。

二、主题

Hugo通过主题将md文件渲染为HTML格式,主题实质是HTML/JavaScript/CSS的集合:

  • HTML:构造页面的标签元素
  • CSS:配置标签元素的样式
  • JavaScript:设置标签元素的动作

若想自定义(修改)主题,首先定位html文件了解主题的架构、使用浏览器的开发者工具(F12)了解标签元素和其样式,然后遵循此页面新建一个HTML/JavaScript/CSS文件(直接修改主题代码是一个坏习惯):

  • 主题的预设部件(themes/hugo-theme-learn/layouts/partials目录):

    layouts/partials目录内自定义一个同名文件(优先级高于主题预设的部件)。

  • 主题的预设CSS(themes/hugo-theme-learn/static/css目录):

    static/css目录内自定义一个css文件(优先级高于主题预设CSS)。

1、安装主题

Hugo没有预设主题,可在Hugo的官方网站(或此GitHub仓库)将目标主题下载(克隆)到Hugo项目根目录内的themes目录中。

  • git clone 主题的git地址 themes/新名称
  1. 进入themes目录(E:/Hugo/sites/ebook/themes

    • E:\Hugo\sites\ebook>cd themes
  2. 安装主题

    推荐:learndocDock(基于learn的移植,最大特色是幻灯片式播放md文件)。

    • $ git clone https://github.com/matcornic/hugo-theme-learn.git
    • Cloning into 'hugo-theme-learn'...
    • remote: Enumerating objects: 2249, done.
    • Receiving objects: 100% (2249/2249), 13.40 MiB | 11.00 KiB/s, done.
    • Resolving deltas: 100% (1224/1224), done.

2、learn主题

learn主题的官方文档: https://learn.netlify.com/

learn主题结构:

  • 网站配置文件:配置网站的基本参数

    themes/hugo-theme-learn/exampleSite/config.toml覆盖项目根目录内的config.toml后,进行自定义修改。

  • 网站布局文件:构造网站的HTML结构

    themes/hugo-theme-learn/layouts/index.html,文件内调用其它html文件、Hugo的页面变量等。

  • 网站样式文件:渲染HTML标签元素的样式

    themes/hugo-theme-learn/static/css,在html文件中引用CSS文件。使用浏览器的开发者工具查看HTML标签元素来源于哪一个CSS文件。

  • 原型文件:内容文件的模板,主要是配置扉页等

    themes/hugo-theme-learn/archetypes,learn主题预设了2个原型文件:

    • chapter.md:构建章节文件(type:chapter)

      将其放入archetypes目录内,作为一个通用模板,方便其它主题调用。

    • default.md:构建文件(type:所有类型)

2.1 网站配置文件

Hugo的网站配置文件(config.toml)配置网站的整体设置,其初始默认设置非常简单:

  • baseURL = "http://example.org/" # 网站URL,运行本地web服务器时不需要此值
  • languageCode = "en-us" # 网站语言
  • title = "My New Hugo Site" # 网站标题

config.toml自定义修改后的结果:

  • baseURL = "http://example.org/"
  • DefaultContentLanguage = "zh-cn"
  • title = "无边风月"
  • theme = "hugo-theme-learn"
  • [outputs]
  • home = [ "HTML", "RSS", "JSON"]
  • [[menu.shortcuts]]
  • name = "<i class='fas fa-user'></i> 简介"
  • url = "/about/"
  • weight = 11
  • [[menu.shortcuts]]
  • name = "<i class='fas fa-align-justify'></i> 分类"
  • url = "/categories/"
  • weight = 12
  • [[menu.shortcuts]]
  • name = "<i class='fas fa-bookmark'></i> 标签"
  • url = "/tags/"
  • weight = 13
  • [markup]
  • [markup.tableOfContents]
  • endLevel = 4
  • startLevel = 2
  • [markup.goldmark.renderer]
  • unsafe = true
  • [params]
  • themeVariant = "mine"
  • author = "komantao"
  • ordersectionsby = "weight"
2.1.1 默认语言

根据主题的语言包(themes/hugo-theme-learn/i18n)内的文件名称配置网站语言:

  • languageCode = "en-us" DefaultContentLanguage = "zh-cn"
2.1.2 params参数
  • [params]
  • editURL = "" # 在每一个页面的右上角位置添加“Edit this page”按钮
  • author = "" # 网站作者名称
  • description = "" # 网站描述
  • showVisitedLinks = false # 值为true时,菜单栏显示已访问的复选标记
  • disableSearch = false # 值为true时,禁用搜索功能,将隐藏搜索栏
  • disableAssetsBusting = false # 值为false时,生成新网站后自动清除Javascript and CSS的缓存
  • disableInlineCopyToClipBoard = false # 值为false时,允许内联代码的“复制到剪贴板”按钮
  • disableShortcutsTitle = false # 值为false时,菜单中快捷键的标题默认设置(等于文章标题)
  • disableLanguageSwitchingButton = false # 值为true时,使用多语言网站时,禁用切换语言按钮
  • disableBreadcrumb = true # 值为true时,隐藏面包屑导航(指页面顶栏的导航),只显示当前页标题
  • disableNextPrev = true # 隐藏“下一页”和“上一页”按钮
  • ordersectionsby = "weight" # 在菜单中按“weight”或“title”排序。默认为“weight”
  • themeVariant = "" # 配色方案。可以是“red”、“blue”、“green”或自定义
2.1.3 markup参数

Hugo v_0.60的Markdown渲染库改用Goldmark(放弃了Blackfriday)。

默认情况下,Goldmark禁止原始HTML和潜在危险的链接。若Markdown文件内有内联HTML或JavaScript,则需要在config.toml内开启unsafe:

  • [markup]
  • [markup.goldmark.renderer]
  • unsafe = false # 缺省值为false,值为true时,md文件可使用html和js语法
  • 慎重开启unsafe选项!!!

    因为Hugo会执行代码块内的HTML源代码,造成版面格式错乱或其它莫名其妙的问题。

配置TOC目录的层级:

  • [markup]
  • [markup.tableOfContents]
  • endLevel = 4
  • startLevel = 1
  • startLevel:设置标题标签的开始层级,在TOC目录内显示的最小层级是H2
    • 若取值为1,在HTML页面构建H1的标签;但不会在TOC目录内显示H1
    • 若取值大于1,在HTML页面不构建指定层级之前的标签
  • endLevel:设置标题标签的结束层级,但在TOC目录内显示的最大层级是H4
    • 若取值小于4,在HTML页面不构建指定层级之后的标签
    • 若取值大于4,根据实际在HTML页面构建标签;但不会在TOC目录内显示H5

配置语法高亮(highlight):

  • [markup]
  • [markup.highlight]
  • codeFences = true
  • hl_Lines = ""
  • lineNoStart = 1
  • lineNos = false
  • lineNumbersInTable = true
  • noClasses = true
  • style = "monokai"
  • tabWidth = 4

由于learn主题在header.htmlfooter.html文件中自定义了语法高亮(本地引用highlight.js)插件,覆盖了Hugo的语法高亮。

2.1.4 搜索功能
  • [outputs]
  • home = [ "HTML", "RSS", "JSON"]

learn主题将使用hugo 20+版本中的最新改进来生成json索引文件,以供lunr.js javascript搜索引擎使用。

Hugo在public文件夹的根目录下生成lunrjs index.json,构建网站(hugo|hugo server)时,在内部生成它(不会显示在文件系统中)。

2.1.5 菜单项

在菜单(menu)中定义其他菜单条目(menu.main)或快捷方式(menu.shortcuts)。

在网站配置文件config.toml中添加快捷方式:

  • [[menu.shortcuts]]
  • name = "<i class='fab fa-github'></i> Github repo"
  • identifier = "ds"
  • url = "https://github.com/matcornic/hugo-theme-learn" # 使用远程仓库地址
  • weight = 10
  • [[menu.shortcuts]]
  • name = "<i class='fas fa-tags'></i> 标签"
  • url = "/tags" # 使用本地地址:tags属性
  • weight = 11
  • [[menu.shortcuts]]
  • name = "<i class='fas fa-camera'></i> 关于"
  • url = "/about.html" # 使用本地地址:自定义属性
  • weight = 11
  • url参数值的来源:

    • 使用远程仓库网址

    • 使用扉页中的属性值,例如:tags属性、categories属性

      1. 在Markdown文件的扉页中设置tag属性,标签按其插入顺序显示在页面的顶部

        • +++
        • date = 2018-11-29T08:41:44+01:00
        • title = Theme tutorial
        • weight = 15
        • tags = ["tutorial", "theme"]
        • +++
      2. 在menu中显示标签

        • [[menu.shortcuts]]
        • name = "<i class='fas fa-tags'></i> Tags"
        • url = "/tags"
        • weight = 30
    • 自定义本地内容文件(示例:关于about)

      1. content根目录内新建一个about.md文件(不需要创建子目录)

      2. config.toml文件中添加快捷方式,自定义name和url

        可以通过更改本地的i18n目录内的语言包配置文件来覆盖(翻译)标题(name)。

        示例:在i18n/en.toml文件,添加以下内容

        • [Shortcuts-Title]
        • other = "<Your value>"

        若设置了disableShortcutsTitle=true,则此标题(name)被禁用。

  • url参数值的写法由uglyurls参数决定:

    • uglyurls = true:丑陋URLs,url应该写为url = "/about.html"
    • uglyurls = false:漂亮URLs,url应该写为url = "/about"

2.2 HTML

learn主题预设的html文件存放路径:themes/hugo-theme-learn/layouts

2.2.1 header

内容页面的header标签(包含导航),不会被覆盖。

themes/hugo-theme-learn/layouts/partials/header.html文件:

  1. 在内容文件中添加以下信息:

    image-20191214131536049

    懒得新建html文件,直接添加:

    1. <head>标签内添加busuanzi的js插件

      • <head>
      • <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
    2. <div id="body-inner">标签内添加一个<p>标签:

      • <div id="body-inner">
      • {{if and (not .IsHome) (not .Params.chapter)}}
      • <br>
      • <h1>{{.Title}}</h1>
      • {{ if not .Data.Terms }}
      • <p class="authorline">
      • {{with .Params.author}}
      • <i class='fa fa-user'></i> <a href="https://github.com/username/username.github.io">{{ . }}</a>
      • {{end}}
      • <span> <i class='fa fa-calendar'></i> {{.Date.Format "2006-01-02"}}</span>
      • <span> <i class="fa fa-wrench" aria-hidden="true"></i> {{.Lastmod.Format "2006-01-02"}}</span>
      • <span> 字数 {{.WordCount}}</span>
      • <span id="busuanzi_container_page_pv"> 阅读量 <span id="busuanzi_value_page_pv"></span></span>
      • </p>
      • <br>
      • {{end}}
      • {{end}}
  2. 自定义语法高亮

    通过CDN(BootCDNstaticfile.org)在线引用Highlight.js插件。

    备注:若Highlight.js插件无法识别编程语言,将无法着色。此时,应该不选择语言或选择近似语言。

    <head>标签内添加:

    • <link href="https://cdn.bootcss.com/highlight.js/9.15.10/styles/zenburn.min.css" rel="stylesheet">
    • <script src="https://cdn.bootcss.com/highlight.js/9.15.10/highlight.min.js"></script>
    • <script>hljs.initHighlightingOnLoad();</script>
    • 第一行:在线引用配色方案monokai.min.css,learn主题本地使用(themes/hugo-theme-learn/static/css/atom-one-dark-reasonable.css),调用文件themes/hugo-theme-learn/layouts/partials/header.html

    • 第二行:在线引用highlight.js压缩版,learn主题本地使用(themes/hugo-theme-learn/static/js/highlight.pack.js),调用文件themes/hugo-theme-learn/layouts/partials/footer.html

    • 第三行:调用highlight.js进行着色(语法高亮)

    因此,若想更改learn主题的语法高亮,只需要修改第一行,即将

    • <link href="{{"css/atom-one-dark-reasonable.css" | relURL}}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">

    修改为:

    • <link href="https://cdn.bootcss.com/highlight.js/9.15.10/styles/zenburn.min.css" rel="stylesheet">
  3. 代码块添加行号

    highlight.js插件本身没有显示行号的功能,百度搜索教程自行添加行号:

    themes/hugo-theme-learn/layouts/partials/footer.html的body标签内的末尾位置添加:

    • <script type="text/javascript">
    • var e = document.querySelectorAll("pre code");
    • var i;
    • for (i = 0; i < e.length; i++) {
    • e[i].innerHTML = "<ul><li>" + e[i].innerHTML.replace(/\n/g, "\n</li><li>") + "\n</li></ul>";
    • $("code ul li").last().remove();
    • }
    • </script>
    • 将代码块(pre)内的代码(code)的换行符\n替换为标签<ul><li>
    • 使用 $("code ul li").last().remove();删除多增加的一行空行

    在CSS文件(static/scc/theme-mine.css)内添加:

    • /* highlight.js插件的语法高亮 */
    • .hljs ul {
    • list-style: decimal;
    • margin: 0 0 0 40px!important;
    • padding: 0
    • }
    • .hljs li {
    • list-style: decimal-leading-zero;
    • border-left: 1px solid #111!important;
    • padding: 2px 5px!important;
    • margin: 0!important;
    • line-height: 14px;
    • width: 100%;
    • box-sizing: border-box
    • }
    • .hljs li:nth-of-type(even) {
    • background-color: rgba(255,255,255,.015);
    • color: inherit
    • }
    • list-style: decimal;是根据<li>标签自动编号
  4. 增加“back to top”按钮

    <div id="body-inner">标签内添加一个<p>标签和js代码:

    • <p id="back-to-top"><i class="fa fa-space-shuttle fa-2x fa-rotate-270" aria-hidden="true"></i></p>
    • <script>
    • var backButton=$('#back-to-top');
    • backButton.hide(); /*首先将#back-to-top隐藏*/
    • function backToTop() {
    • $('html,body').animate({scrollTop: 0}, 800);
    • return false;
    • }
    • backButton.on('click', backToTop);
    • $(window).on('scroll', function () {/*当滚动条的垂直位置大于浏览器所能看到的页面的那部分的高度时,回到顶部按钮就显示 */
    • if ($(window).scrollTop() > $(window).height())
    • backButton.fadeIn();
    • else
    • backButton.fadeOut();
    • });
    • $(window).trigger('scroll');/*触发滚动事件,避免刷新的时候显示回到顶部按钮*/
    • </script>

    然后在CSS文件中设置样式:

    • /* 回到顶部按钮 */
    • p#back-to-top{
    • position:fixed;
    • bottom:6%;
    • right:3%;
    • }
    • p#back-to-top i{
    • color:blue;
    • display:block;
    • z-index: -100;
    • }
    • p#back-to-top i:hover{
    • color:red;
    • }
2.2.2 favicon

网站图标(在浏览器的标题内显示)。

layouts/partials目录内新建一个文件,命名favicon.html。然后编写HTML。使用<link>标签并引用在static文件夹内的图像(假设在static/images目录内)。

  • <link rel="shortcut icon" href="/images/favicon.png" type="image/x-icon" />

网站徽标(在页面左上角显示)。

layouts/partials目录内新建一个文件,命名logo.html。然后编写想要的任何HTML。使用img标签并引用在static文件夹内的图像(假设在static目录内)。

  • <a id="logo" href="{{ .Site.BaseURL }}">
  • <img class="custom-logo" src="夜空.jpg">
  • </a>

左侧菜单的页脚。

  • <p>Theme:<a href="https://getgrav.org">Grav</a> and <a href="https://gohugo.io/">Hugo</a></p>

2.3 CSS

learn主题预设的CSS文件存放路径:themes/hugo-theme-learn/static/css

预设了3种CSS配色方案(red、blue、green),直接在config.toml修改参数即可使用:

  • [params]
  • themeVariant = "green"

自定义CSS配色方案:在static/css目录内新建一个CSS文件(文件名使用theme前缀,例如theme-mine.css)。

  • :root{
  • /* body标签:文章正文 */
  • --MAIN-TEXT-color:#323232; /* 缺省颜色 */
  • --MAIN-TITLES-TEXT-color: #5e5e5e; /* h2-h3-h4-h5标题的颜色 */
  • --MAIN-LINK-color:#1C90F3; /* a标签:链接(links)的颜色 */
  • --MAIN-LINK-HOVER-color:#DC143C; /* 悬停在链接时的颜色 */
  • --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */
  • /* nav标签:导航栏(或称侧边栏、菜单栏) */
  • /* #sidebar #header-wrapper:导航栏内的header,包括网站图标和搜索栏 */
  • --MENU-HEADER-BG-color:#FFFFF0; /* 导航栏内的header的背景颜色 */
  • --MENU-HEADER-BORDER-color:#33a1ff; /* 导航栏内的header的边框颜色 */
  • --MENU-WIDTH:15em; /* 导航栏相对宽度 */
  • /* #sidebar .searchbox:导航栏内的搜索栏 */
  • --MENU-SEARCH-BG-color:#D3D3D3; /* 搜索栏的背景颜色 */
  • --MENU-SEARCH-BOX-color: #33a1ff; /* 搜索栏的边框颜色 */
  • --MENU-SEARCH-BOX-ICONS-color: #000000; /* 搜索栏中的图标的颜色 */
  • /* #sidebar ul.topics > li.parent, #sidebar ul.topics > li.active:活动组件,指被选中的章节或其内容 */
  • --MENU-SECTIONS-BG-color:#E0FFFF; /* 导航栏的缺省颜色 */
  • --MENU-SECTIONS-LINK-color: #000000; /* 导航栏内链接的颜色 */
  • --MENU-SECTIONS-LINK-HOVER-color: #FF0000; /* 导航栏内链接悬停时的颜色 */
  • --MENU-SECTIONS-ACTIVE-BG-color:#D3D3D3; /* 活动组件(active section,被选中时)的背景颜色,包含子组件 */
  • --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* 活动组件的颜色 */
  • --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #FDF5E6; /* 活动组件的背景颜色 */
  • --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */
  • --MENU-SECTION-HR-color: #20272b; /* Color of <hr> separator in menu */
  • }
  • body {
  • color: var(--MAIN-TEXT-color) !important;
  • }
  • #body .padding {
  • padding: 15px 1rem;
  • }
  • #sidebar {
  • width: var(--MENU-WIDTH) !important;
  • }
  • #body {
  • margin-left: var(--MENU-WIDTH) !important;
  • }
  • textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
  • border-color: none;
  • box-shadow: none;
  • }
  • h1 {
  • background: var(--MENU-SECTIONS-BG-color);
  • font-weight: 700;
  • }
  • #chapter h1 {
  • border-bottom: none;
  • }
  • #chapter p {
  • text-align: left;
  • }
  • h2, h3, h4, h5 {
  • color: var(--MAIN-TITLES-TEXT-color) !important;
  • }
  • h2 {
  • font-size: 1.8em;
  • margin: 20px 0;
  • padding-left: 0px;
  • font-weight: 700;
  • line-height: 1.4;
  • background: var(--MENU-HEADER-BORDER-color);
  • }
  • h3 {
  • font-weight: 700;
  • font-size: 1.2em;
  • line-height: 1.4;
  • margin: 10px 0 5px;
  • padding-top: 10px;
  • }
  • h4 {
  • font-weight: 700;
  • /* text-transform: uppercase; 控制文本的大小写:uppercase 大写 */
  • font-size: 1.1em;
  • line-height: 1.4;
  • margin: 10px 0 5px;
  • padding-top: 10px
  • }
  • h5, h6 {
  • font-size: 1em;
  • }
  • a {
  • color: var(--MAIN-LINK-color);
  • }
  • .anchor {
  • color: var(--MAIN-ANCHOR-color);
  • }
  • a:hover {
  • color: var(--MAIN-LINK-HOVER-color);
  • }
  • #sidebar ul li.visited > a .read-icon {
  • color: var(--MENU-VISITED-color);
  • }
  • #body a.highlight:after {
  • display: block;
  • content: "";
  • height: 1px;
  • width: 0%;
  • -webkit-transition: width 0.5s ease;
  • -moz-transition: width 0.5s ease;
  • -ms-transition: width 0.5s ease;
  • transition: width 0.5s ease;
  • background-color: var(--MAIN-LINK-HOVER-color);
  • }
  • #sidebar {
  • background-color: var(--MENU-SECTIONS-BG-color);
  • }
  • #sidebar #header-wrapper {
  • background: var(--MENU-HEADER-BG-color);
  • color: var(--MENU-SEARCH-BOX-color);
  • border-color: var(--MENU-HEADER-BORDER-color);
  • }
  • #sidebar .searchbox {
  • border-color: var(--MENU-SEARCH-BOX-color);
  • background: var(--MENU-SEARCH-BG-color);
  • }
  • #sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
  • background: var(--MENU-SECTIONS-ACTIVE-BG-color);
  • }
  • #sidebar .searchbox * {
  • color: var(--MENU-SEARCH-BOX-ICONS-color);
  • }
  • #sidebar a {
  • color: var(--MENU-SECTIONS-LINK-color);
  • font-weight: 400;
  • }
  • #sidebar a:hover {
  • color: var(--MENU-SECTIONS-LINK-HOVER-color) !important;
  • }
  • #sidebar ul li.active > a {
  • background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
  • color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
  • }
  • #sidebar hr {
  • border-color: var(--MENU-SECTION-HR-color);
  • }
  • #sidebar ul.topics ul a {
  • color: #1E90FF;
  • }
  • #sidebar section#shortcuts {
  • background: #DDA0DD;
  • }
  • #body #navigation {
  • display: none;
  • }
  • /* 设置TOC */
  • #TableOfContents > ul > li > a {
  • padding: 0;
  • color: #000000;
  • }
  • #TableOfContents > ul > li > ul > li > a {
  • padding: 0 20px;
  • }
  • #TableOfContents > ul > li > ul > li > ul > li > a {
  • padding: 0 25px;
  • }
  • /* 设置代码块 */
  • #body-inner pre {
  • max-height: 300px;
  • overflow: auto;
  • padding: 0;
  • margin: 0;
  • white-space: pre;
  • }
  • #body img, #body .video-container {
  • margin: 1rem auto;
  • }
  • /* 设置表格 */
  • table th {
  • background: #999999;
  • text-align: center;
  • }
  • table th, table td {
  • border: 1px solid #000000;
  • padding: 0.2rem;
  • }
  • /* 设置引用 */
  • blockquote {
  • background: #F5F5F5;
  • border-left: 4px solid #0066FF;
  • }

自定义配色方案后,在config.toml中配置参数:

  • [params]
  • themeVariant = "mine"

2.4 图标和徽标

Hugo-theme-learn主题已加载了Font Awesome库,可以轻松显示Font Awesome中的免费图标(icon)或徽标(logo)。

浏览旧版本的Font Awesome库(v5.12不能预览图标)选择好图标(例如heart)后,复制其HTML后粘贴到Markdown文件中:

  • <i class="fas fa-heart"></i>
  • docDock主题默认内置font-awesome.min.css(不支持fas图标)
  • learn主题默认内置fontawesome-all.min.css(支持fas图标)

3、docDock主题

Hugo-theme-docDock主题教程:

Hugo-theme-docDock主题结构:

  • 网站配置文件:配置网站的基本参数

    themes/hugo-theme-docdock/exampleSite/config.toml覆盖项目根目录内的config.toml后,进行自定义修改。

  • 网站页面布局文件:构建页面的HTML结构

    路径:themes/hugo-theme-docdock/layouts

    • 页面文件模板:_default/baseof.html
    • 单体页面模板:_default/single.html,例如:构建md文件的页面
    • 列表页面模板:_default/list.html,例如:构建tags或categories的页面
    • 列表页面模板:_default/li.html,构建docDock主题的tags首页
    • 章节页面模板:index.html
  • 网站样式文件:渲染HTML标签元素的样式

    路径:themes/hugo-theme-docdock/static/css。html文件引用CSS文件,使用浏览器的开发者工具可查看HTML标签元素来源于哪一个CSS文件。

  • 原型文件:themes/hugo-theme-learn/archetypes

    learn主题预设了2个原型文件(生成内容文件的模板):

    • slide.md:构建章节文件(type:slide,幻灯片)
    • default.md:构建文件(type:所有类型)

docDock主题移植于learn主题,因此,可参考learn主题的配置。

3.1 网站配置文件

参考示例自定义修改config.toml为:

  • baseURL = "https://kuang.netlify.com/" # 发布网站的URL
  • languageCode = "en" # 网站语言
  • defaultContentLanguage = "zh-cn" # 没有语言指示符的内容将默认为这种语言
  • title = "风月" # 网站名称
  • theme = "hugo-theme-docdock" # 启用主题
  • enableRobotsTXT = true # 生成robots.txt,告诉搜索引擎允许其抓取所有内容
  • enableEmoji = true # 启用表情符号
  • hasCJKLanguage = true # true时,自动检测内容中的中文/日语/韩语。这将使.Summary和.WordCount正确识别CJK语言
  • enableGitInfo = true # Lastmod项使用Git的最后提交时间
  • relativeURLs = true # URL相对于content目录
  • canonifyURLs = true # 将相对URL转换为绝对
  • paginate = 10 # 分布(pagination)中每页的默认元素数量。但分页失败,建议填写一个较大值,避免渲染失败
  • PaginatePath = "page"
  • buildDrafts = false # 构建(build)时,true表示包含草稿(drafts)
  • [outputs]
  • home = [ "HTML", "RSS", "JSON"]
  • [[menu.shortcuts]]
  • name = "<i class='fa fa-th'></i> 分类"
  • url = "/categories"
  • weight = 12
  • [[menu.shortcuts]]
  • name = "<i class='fa fa-tags'></i> 标签"
  • url = "/tags"
  • weight = 13
  • [markup]
  • [markup.tableOfContents]
  • endLevel = 6 # TOC的标题结束层数(H6)
  • startLevel = 1 # TOC的标题开始层数(H1)
  • [markup.goldmark.renderer]
  • unsafe = false
  • [params]
  • author = "komantao" # 作者
  • authorsdescribe = "一缕风尘空蒙 一泓月色潋滟" # 作者描述
  • description = "学习笔记" # 网站描述,方便SEO
  • github = true # 社交链接
  • editURL = "" # 顶栏显示“Edit this page”(输入content目录在源代码仓库内的URL)
  • themeStyle = "original" # docDock主题预设有2种类型:"original"、"flex"(缺省值)
  • themeVariant = "mine" # 主题变体(即CSS配色方案)预设值有:"green"、"gold"、"gray"、"blue"(缺省值),可自定义新的变体
  • ordersectionsby = "weight" # 章节(sections)排序:weight(自定义排序权重值)、title(缺省值,按照文档的title排序)
  • disableHomeIcon = false # true时,禁止显示网站主页图标;缺省值为false
  • disableSearch = false # true时,禁止搜索;缺省值为false
  • disableNavChevron = true # true时,隐藏上一页/下一页导航(next/prev chevron);缺省值为false
  • highlightClientSide = true # true时,使用highlight.pack.js插件,从而代替hugo默认的chroma highlighter
  • menushortcutsnewtab = true # true时,在新的标签页打开菜单项的链接(shortcuts links),但貌似无效;缺省值为false
  • disableAssetsBusting = false
  • copyrighthtml = "Copyright &#xA9; 2020 komantao. All Rights Reserved." # 自定义版权信息
  • enableGitalk = true
  • [params.reward] # 设置打赏功能
  • enable = true
  • wechat = "/images/wechat.png" # 微信二维码
  • [params.gitalk] # 使用Gitalk设置评论区
  • clientID = "xxx" # GitHub应用程序(Gitalk)生成的client ID
  • clientSecret = "xxx" # GitHub应用程序(Gitalk)生成的client secret
  • repo = "discuss" # 存储评论(comments)的GitHub仓库名
  • owner = "xxx" # GitHub仓库的所有者(owner)的GitHub ID
  • admin= "xxx" # GitHub仓库的所有者和合作者(collaborators),指对仓库具有写访问权限的用户
  • id= "location.pathname" # 页面的唯一ID
  • labels= "gitalk" # Github的issue标签
  • perPage= 15 # 分页大小(Pagination size),最大为100
  • pagerDirection= "last" # 评论排序方向,可用值为'last'和'first'
  • createIssueManually= true # false时, 在评论仓库的issue内自动显示管理员登录信息
  • distractionFreeMode= false # false时,启用热键(cmd|ctrl + enter)提交评论
  • paginate

    Hugo_v0.6自动分页失败,建议将paginate值设置为一个较大值,避免渲染失败:

    ERROR 2020/02/14 11:27:41 failed to render pages: render of “taxonomyTerm” failed: “E:\Hugo\sites\book\themes\hugo-theme-docdock\layouts_default\list.html:7:42”: execute of template failed: template: _default\list.html:8:3: executing “main” at <partial “pagination.html” $paginator>: error calling partial: “E:\Hugo\sites\book\themes\hugo-theme-docdock\layouts\partials\pagination.html:7:42”: execute of template failed: template: partials/pagination.html:7:42: executing “partials/pagination.html” at <.Next.RelPermalink>: can't evaluate field RelPermalink in type *page.Pager

  • 启用highlight.js

    • [params]
    • highlightClientSide = true

    同时,禁用(注释或删除)pygments( 从0.30版本开始,被Chroma替代 )

    • # pygmentsCodeFences = true
    • # pygmentsStyle = "monokailight"

3.2 HTML

在导航栏内(<div id="header">标签)显示网站logo。

  1. 新建一个logo.html存入layouts/partials目录

    • <a id="logo" href="{{ .Site.BaseURL }}">
    • <img class="custom-logo" src="/images/风车.gif"> /* 网站logo图片存放在static/images目录内 */
    • </a>
  2. 调用logo.html

    themes/hugo-theme-docdock/layouts/partials/original/body-beforecontent.html文件(<div id="header">标签)内调用logo.html

    • <div id="header">
    • {{ partial "logo.html" . }}
3.2.2 header

导航栏内(<div id="header">标签)显示作者、作者描述、网站描述和社交链接等。

  1. config.toml中设置选项开关

    • [params]
    • author = "komantao" # 作者
    • authorsdescribe = "一缕风尘空蒙 一泓月色潋滟" # 作者描述
    • description = "学习笔记" # 网站描述,方便SEO
    • github = true # 社交链接
  2. 添加HTML标签

    • {{with .Site.Params.author}} /* 添加作者标签 */
    • <a>{{ . }}</a>
    • {{end}}
    • <br/>
    • {{with .Site.Params.authorsdescribe}} /* 添加作者描述标签 */
    • <span style="white-space: pre;">{{ . }}</span>
    • {{end}}
    • <br/>
    • {{with .Site.Params.github}} /* 添加社交标签 */
    • <a href="https://github.com/xxx/xxx.github.io"><i class="fa fa-github" aria-hidden="true"></i></a>
    • {{end}}
3.2.3 导航栏标题

在导航栏的列表(<ul class="topics">标签)内增加一个标记,显示为“目录”。

themes/hugo-theme-docdock/layouts/partials/original/body-beforecontent.html中的<ul class="topics">标签内新增一个标签:

  • <ul class="topics">
  • <a>目录:</a>

显示效果:

image-20191217230519267

同理,在导航栏的<section id="shortcuts">标签内增加一个标题,显示为“其它”并修改为:

  • <section id="shortcuts">
  • <a>其它:</a>
  • {{- range sort . "Weight"}}
  • <li class="" role="">
  • {{- .Pre -}}
  • <a href="{{.URL}}" target="_blank" rel="noopener">{{safeHTML .Name}}</a>
  • {{- .Post -}}
  • </li>
  • {{- end}}
  • </section>
  • <a>标签内的target="_blank",表示新建页面打开链接。若删除,在原页面打开链接
3.2.4 Top Bar
3.2.4 标签页

docdock主题预设了一个tags首页,点击页面内的标签(区别于点击导航栏内的tags快捷键)弹出的首页,文件路径为:themes/hugo-theme-docdock/layouts/_default/li.html

3.2.5 文章信息

在文章开始位置增加以下信息:

image-20191214131536049

  1. 添加busuanzi的js插件

    themes/hugo-theme-docdock/layouts/partials/original/head.html文件中添加:

    • <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"> </script>
  2. 设置config.toml

    • hasCJKLanguage = true # 若为true,则自动检测内容中的中文/日语/韩语。这将使.Summary和.WordCount正确识别CJK语言
  3. 添加html标签

    themes/hugo-theme-docdock/layouts/partials/original/body-beforecontent.html文件中的<div id="body-inner">标签内添加一个<p>标签:

    • <div id="body-inner">
    • {{if and (not .IsHome) (not .Params.chapter)}}
    • <br>
    • <br>
    • <h1>{{.Title}}</h1>
    • {{ if not .Data.Terms }}
    • <p class="authorline">
    • {{with .Params.author}}
    • <i class='fa fa-user'></i> <a>{{ . }}</a>
    • {{end}}
    • <span> <i class='fa fa-calendar'></i> {{.Date.Format "2006-01-02"}}</span>
    • <span> <i class="fa fa-wrench" aria-hidden="true"></i> {{.Lastmod.Format "2006-01-02"}}</span>
    • <span> 字数 {{.WordCount}}</span>
    • <span id="busuanzi_container_page_pv"> 阅读量 <span id="busuanzi_value_page_pv"></span></span>
    • </p>
    • <br>
    • {{end}}
    • {{end}}
3.2.6 Highlight.js
  1. 开启Highlight.js

    docdock主题已在本地安装了Highlight.js插件,在themes/hugo-theme-docdock/layouts/partials/original/scripts.html文件中调用themes/hugo-theme-docdock/static/js/highlight.pack.js,但只使用了缺省的配色方案。

    config.toml中开启Highlight.js:

    • [params]
    • highlightClientSide = true

    或通过CDN(BootCDNstaticfile.org)在线引用Highlight.js插件。

    themes/hugo-theme-docdock/layouts/partials/original/head.html文件中添加:

    • <link href="https://cdn.bootcss.com/highlight.js/9.15.10/styles/zenburn.min.css" rel="stylesheet">
    • <script src="https://cdn.bootcss.com/highlight.js/9.15.10/highlight.min.js"></script>
    • <script>hljs.initHighlightingOnLoad();</script>
    • 第一行:在线引用zenburn.min.css配色方案

    • 第二行:在线引用highlight.js插件

    • 第三行:调用highlight.js进行着色(语法高亮)

  2. 着色(选择配色方案)

    若选择了Highlight.js插件不能识别的语言,将会着色失败,从而导致后面的添加行号也失败。解决方法是清空"选择语言"内容,Highlight.js将使用默认着色。

    若想更改配色方案,只需要修改第一行:

    • <link href="https://cdn.bootcss.com/highlight.js/9.15.10/styles/zenburn.min.css" rel="stylesheet">
  3. 代码块添加行号

    highlight.js插件本身不能显示行号,百度搜索教程自行添加行号。

    themes/hugo-theme-docdock/layouts/partials/original/body-aftercontent.html文件的{{ partial "custom-content-footer.html" . }}后面添加:

    • <script type="text/javascript">
    • var e = document.querySelectorAll("pre code");
    • var i;
    • for (i = 0; i < e.length; i++) {
    • e[i].innerHTML = "<ul><li>" + e[i].innerHTML.replace(/\n/g, "\n</li><li>") + "\n</li></ul>";
    • $("code ul li").last().remove();
    • }
    • </script>
    • 将代码块(pre)内的代码(code)的换行符\n替换为标签<ul><li>
    • 使用 $("code ul li").last().remove();删除多增加的一行空行

    themes/hugo-theme-docdock/static/theme-original/variant-mine.css文件内添加:

    • /* highlight.js插件的语法高亮 */
    • .hljs ul {
    • list-style: decimal;
    • margin: 0 0 0 40px !important;
    • padding: 0;
    • }
    • .hljs li {
    • list-style: decimal-leading-zero;
    • border-left: 1px solid #111!important;
    • padding: 2px 5px!important;
    • margin: 0!important;
    • line-height: 14px;
    • width: 100%;
    • box-sizing: border-box;
    • }
    • .hljs li:nth-of-type(even) {
    • background-color: rgba(255,255,255,.015);
    • color: inherit;
    • }
    • .copy-to-clipboard {
    • display: none;
    • }
    • pre .copy-to-clipboard {
    • display: inline-block!important;
    • top: 0;
    • right: 0;
    • }
    • list-style: decimal;是根据<li>标签自动编号
  4. 复制按钮

    docDock主题的代码块已设计了复制按钮(Copy to clipboard)。代码块(<pre code>标签)设置最大高度(添加滑条)和将复制按钮固定在<pre>标签内、<code>标签外(复制按钮不承滑条而滚动):

    • /* 设置代码块 */
    • #body-inner pre {
    • background: black;
    • padding: 1.5rem 0 0 0!important; /* 增加顶部边距,为复制按钮预留空间 */
    • margin: 0;
    • white-space: pre;
    • }
    • #body-inner pre code {
    • max-height: 300px; /* 设置最大高度 */
    • overflow: auto; /* 自动滚动 */
    • }
    • pre .copy-to-clipboard {
    • display: inline-block!important;
    • top: 0; /* 复制按钮位置 */
    • right: 0; /* 复制按钮位置 */
    • }
3.2.7 back to top

在页面增加“back to top”按钮。

themes/hugo-theme-docdock/layouts/partials/original/body-aftercontent.html文件的{{ partial "custom-content-footer.html" . }}后面添加一个<p>标签和js代码:

  • <p id="back-to-top"><i class="fa fa-space-shuttle fa-2x fa-rotate-270" aria-hidden="true"></i></p>
  • <script>
  • var backButton=$('#back-to-top');
  • backButton.hide(); /*首先将#back-to-top隐藏*/
  • function backToTop() {
  • $('html,body').animate({scrollTop: 0}, 800);
  • return false;
  • }
  • backButton.on('click', backToTop);
  • $(window).on('scroll', function () { /*当滚动条的垂直位置大于浏览器所能看到的页面的那部分的高度时,回到顶部按钮就显示 */
  • if ($(window).scrollTop() > $(window).height())
  • backButton.fadeIn();
  • else
  • backButton.fadeOut();
  • });
  • $(window).trigger('scroll'); /*触发滚动事件,避免刷新的时候显示回到顶部按钮*/
  • </script>

themes/hugo-theme-docdock/static/theme-original/variant-mine.css文件内添加:

  • /* 回到顶部按钮 */
  • p#back-to-top{
  • position: fixed;
  • bottom: 22%;
  • right: 1%;
  • }
  • p#back-to-top i{
  • color: #1E90FF;
  • display: block;
  • z-index: -100;
  • }
  • p#back-to-top i:hover{
  • color: red;
  • }
3.2.8 页脚

docdock主题页脚(footer):themes/hugo-theme-docdock/layouts/partials/custom-content-footer.html

  • <footer class=" footline" >
  • {{with .Params.LastModifierDisplayName}}
  • <i class='fa fa-user'></i> <a href="mailto:{{ $.Params.LastModifierEmail }}">{{ . }}</a> {{with $.Date}} <i class='fa fa-calendar'></i> {{ .Format "2006/01/02" }}{{end}}
  • </div>
  • {{end}}

在页脚(footer)中增加打赏和版权信息。

  1. config.toml文件增加:

    • [params]
    • copyrighthtml = "Copyright &#xA9; 2020 Komantao. All Rights Reserved."
    • [params.reward] # 打赏
    • enable = true
    • wechat = "/images/wechat.png" # 微信收款二维码
    • 在每年的1月1日,修改“2020”为当前年份
  2. 在页脚文件末尾添加:

    • {{if and (not .IsHome) (not .Params.chapter) (not .Data.Terms)}}
    • {{if .Site.Params.reward.enable}}
    • <p style="text-align: center">感谢您的赞赏支持:</p>
    • <img class="wechat" src="/images/wechat.png" style="max-width:30%">
    • {{end}}
    • {{ if .Site.Params.copyrighthtml }}
    • <div class="text-center" style="text-align: center">{{.Site.Params.CopyrightHTML | safeHTML}}</div>
    • {{ end }}
    • {{ end }}
3.2.9 打开图片

在新标签页打开图片。

themes/hugo-theme-docdock/layouts/partials/original/body-aftercontent.html<div id="body-inner">标签末尾位置添加:

  • <script type="text/JavaScript" language="javascript">
  • <!--给页面中所有img对象添加onclick事件 -->
  • function AddImgClickEvent(){
  • var objs = document.getElementsByTagName("img");
  • for(var i=0;i<objs.length;i++){
  • objs[i].onclick=function(){
  • window.open(this.src);
  • }
  • objs[i].style.cursor = "pointer";
  • }
  • }
  • AddImgClickEvent();
  • </script>

3.3 CSS

mine.css命名为variant-mine.css,存放在themes/hugo-theme-docdock/static/theme-original目录内:

  • :root{
  • /* body标签:文章正文 */
  • --MAIN-TEXT-color:#323232; /* 缺省颜色 */
  • --MAIN-TITLES-TEXT-color: #5e5e5e; /* h2-h3-h4-h5标题的颜色 */
  • --MAIN-LINK-color:#1C90F3; /* a标签:链接(links)的颜色 */
  • --MAIN-LINK-HOVER-color:#DC143C; /* 悬停在链接时的颜色 */
  • --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */
  • /* nav标签:导航栏(或称侧边栏、菜单栏) */
  • /* #sidebar #header-wrapper:导航栏内的header,包括网站图标和搜索栏 */
  • --MENU-HEADER-BG-color:#E0FFFF; /* 导航栏内的header的背景颜色 */
  • --MENU-HEADER-BORDER-color:#33a1ff; /* 导航栏内的header的边框颜色 */
  • --MENU-WIDTH:16em; /* 导航栏相对宽度 */
  • /* #sidebar .searchbox:导航栏内的搜索栏 */
  • --MENU-SEARCH-BG-color:#D3D3D3; /* 搜索栏的背景颜色 */
  • --MENU-SEARCH-BOX-color: #33a1ff; /* 搜索栏的边框颜色 */
  • --MENU-SEARCH-BOX-ICONS-color: #000000; /* 搜索栏中的图标的颜色 */
  • /* #sidebar ul.topics > li.parent, #sidebar ul.topics > li.active:活动组件,指被选中的章节或其内容 */
  • --MENU-SECTIONS-BG-color:#E0FFFF; /* 导航栏的缺省颜色 */
  • --MENU-SECTIONS-LINK-color: #000000; /* 导航栏内链接的颜色 */
  • --MENU-SECTIONS-LINK-HOVER-color: #FF0000; /* 导航栏内链接悬停时的颜色 */
  • --MENU-SECTIONS-ACTIVE-BG-color: #87CEFA; /* 活动组件(active section,被选中时)的背景颜色,包含子组件 */
  • --MENU-SECTION-ACTIVE-CATEGORY-color: #000000; /* 活动组件的颜色 */
  • --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #FDF5E6; /* 活动组件的背景颜色 */
  • --MENU-SECTION-HR-color: #20272b; /* 导航栏<hr>分隔符的颜色 */
  • }
  • /* body标签 */
  • body {
  • color: var(--MAIN-TEXT-color) !important;
  • font-family: -apple-system,BlinkMacSystemFont,Helvetica Neue,Microsoft YaHei,Source Han Sans CN,Source Han Sans SC,Noto Sans CJK SC,WenQuanYi Micro Hei,sans-serif;
  • font-weight: 200;
  • font-size: 16px !important;
  • }
  • /* 导航栏(侧边栏):nav#sidebar */
  • #sidebar {
  • max-width: var(--MENU-WIDTH) !important;
  • background-color: var(--MENU-SECTIONS-BG-color);
  • }
  • #sidebar #header-wrapper {
  • background: var(--MENU-HEADER-BG-color);
  • border-bottom: 3px solid var(--MENU-HEADER-BORDER-color);
  • }
  • #sidebar #header-wrapper #header a.baselink {
  • font-weight: 800;
  • font-size: 28px !important;
  • }
  • #sidebar #header-wrapper #header span {
  • color: #b22222;
  • }
  • #sidebar .searchbox {
  • border-color: var(--MENU-SEARCH-BOX-color);
  • background: var(--MENU-SEARCH-BG-color);
  • }
  • #sidebar .searchbox * {
  • color: var(--MENU-SEARCH-BOX-ICONS-color);
  • }
  • #sidebar ul.topics > a, #sidebar ul.topics section#shortcuts > a {
  • font-weight: 800;
  • font-size: 20px !important;
  • }
  • #sidebar ul.topics > li.parent, #sidebar ul.topics > li.active {
  • background: var(--MENU-SECTIONS-ACTIVE-BG-color);
  • }
  • #sidebar ul.topics li.active > div > a {
  • background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color);
  • color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important;
  • font-weight: 800 !important;
  • }
  • #sidebar a {
  • color: var(--MENU-SECTIONS-LINK-color);
  • font-weight: 400;
  • padding: 0 !important;
  • width: calc(100%) !important;
  • }
  • #sidebar a:hover {
  • color: var(--MENU-SECTIONS-LINK-HOVER-color) !important;
  • }
  • #sidebar hr {
  • border-color: var(--MENU-SECTION-HR-color);
  • }
  • #sidebar section#shortcuts {
  • border-top: 3px solid var(--MENU-HEADER-BORDER-color);
  • }
  • #sidebar .parent li, #sidebar .active li{
  • border-left:1px solid red;
  • }
  • #body .nav{
  • width:1.2rem;
  • }
  • /* 文章正文:section#sidebar */
  • @media only screen and (min-width: 780px) { /* 媒体判断:判断PC浏览器和手机屏幕像素自动调用不同CSS的代码 */
  • #body {
  • margin-left: 15em!important;
  • }
  • #body .padding {
  • padding: 0.5rem 2rem 0.5rem 2rem;
  • }
  • #top-github-link {
  • position: fixed;
  • }
  • }
  • #body a.highlight:after {
  • display: block;
  • content: "";
  • height: 1px;
  • width: 0%;
  • -webkit-transition: width 0.5s ease;
  • -moz-transition: width 0.5s ease;
  • -ms-transition: width 0.5s ease;
  • transition: width 0.5s ease;
  • background-color: var(--MAIN-LINK-HOVER-color);
  • }
  • /* 固定文章顶栏:#top-bar */
  • #top-bar {
  • width: 100%;
  • position: fixed; top: 0;
  • z-index: 99;
  • background: #FFEBCD;
  • margin: 0rem -1rem 1rem;
  • }
  • #breadcrumbs {
  • display: inline-block;
  • }
  • #top-github-link {
  • top: 1.6rem;right: 3rem;
  • z-index: 199;
  • display: inline-block;
  • }
  • /* 文章标签:#tags */
  • #tags {
  • margin-top: 1.8rem;
  • }
  • #tags a.label {
  • background-color: #EE82EE;
  • }
  • /* 文章顶栏中的TOC:#body div#top-bar div.progress nav#TableOfContents */
  • #TableOfContents {
  • padding: 2px !important;
  • }
  • /* 第二层 */
  • #TableOfContents > ul > li > ul > li > a {
  • padding: 0;
  • color: #000000;
  • }
  • /* 第三层 */
  • #TableOfContents > ul > li > ul > li > ul > li > a {
  • padding: 0 20px;
  • }
  • /* 第四层 */
  • #TableOfContents > ul > li > ul > li > ul > li > ul > li > a {
  • padding: 0 30px;
  • color: #FFA500;
  • }
  • textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus {
  • border-color: none;
  • box-shadow: none;
  • }
  • div#body-inner > p.authorline {
  • text-align: center;
  • background-color: #E0FFFF;
  • border-bottom: 1px dashed #183f81!important;
  • }
  • h1, h2, h3, h4, h5, h6 {
  • color: var(--MAIN-TITLES-TEXT-color) !important;
  • font-weight: 700 !important;
  • }
  • h1 {
  • color: red!important;
  • }
  • h2 {
  • font-size: 1.8em;
  • margin: 20px 0;
  • padding-left: 0px;
  • line-height: 1.4;
  • }
  • h3 {
  • font-size: 1.2em;
  • line-height: 1.4;
  • margin: 10px 0 5px;
  • padding-top: 10px;
  • }
  • h4 {
  • /* text-transform: uppercase; 控制文本的大小写:uppercase 大写 */
  • font-size: 1.1em;
  • line-height: 1.4;
  • margin: 10px 0 5px;
  • padding-top: 10px
  • }
  • h5, h6 {
  • font-size: 1.2em;
  • }
  • a {
  • color: var(--MAIN-LINK-color);
  • }
  • .anchor {
  • color: var(--MAIN-ANCHOR-color);
  • }
  • a:hover {
  • color: var(--MAIN-LINK-HOVER-color) !important;
  • }
  • /* 设置表格 */
  • table th {
  • background: #999999;
  • text-align: center;
  • }
  • table th, table td {
  • border: 1px solid #000000;
  • padding: 0.2rem;
  • }
  • /* 设置引用 */
  • blockquote {
  • background: #E0FFFF;
  • border-left: 4px solid #0066FF;
  • }
  • blockquote p,blockquote ul {
  • margin: 0.5rem !important;
  • }
  • /* 设置代码块 */
  • #body-inner pre {
  • background: black;
  • padding: 1.5rem 0 0 0!important;
  • margin: 0;
  • white-space: pre;
  • }
  • code {
  • white-space:pre-wrap;
  • }
  • #body-inner pre code {
  • max-height: 300px;
  • overflow: auto;
  • }
  • #body img, #body .video-container {
  • margin: 1rem auto;
  • }
  • /* highlight.js插件的语法高亮 */
  • .hljs ul {
  • list-style: decimal;
  • margin: 0 0 0 40px !important;
  • padding: 0;
  • }
  • .hljs li {
  • list-style: decimal-leading-zero;
  • border-left: 1px solid #111!important;
  • padding: 2px 5px!important;
  • margin: 0!important;
  • line-height: 14px;
  • width: 100%;
  • box-sizing: border-box;
  • }
  • .hljs li:nth-of-type(even) {
  • background-color: rgba(255,255,255,.015);
  • color: inherit;
  • }
  • .copy-to-clipboard {
  • display: none;
  • }
  • pre .copy-to-clipboard {
  • display: inline-block!important;
  • top: 0;
  • right: 0;
  • }
  • /* 回到顶部按钮 */
  • p#back-to-top{
  • position: fixed;
  • bottom: 22%;
  • right: 1%;
  • }
  • p#back-to-top i{
  • color: #1E90FF;
  • display: block;
  • z-index: -100;
  • }
  • p#back-to-top i:hover{
  • color: red;
  • }

Top Bar,文章页面顶部的导航栏,包含4部分:

image-20200122121955654

  • 1:sidebar开关,在小屏幕时显示或隐藏sidebar
  • 2:TOC目录
  • 3:面包屑(breadcrumb)导航,显示路径
  • 4:GitHub源代码仓库内此文章的代码(code)页面,使用GItHub的"Edit-this-page"插件

页面滚动时固定顶栏:

  • /* 固定文章顶栏:#top-bar */
  • #top-bar {
  • width: 100%;
  • position: fixed; top: 0;
  • z-index: 99;
  • background: #FFEBCD;
  • margin: 0rem -1rem 1rem;
  • }
  • #breadcrumbs {
  • display: inline-block;
  • }
  • #top-github-link {
  • top: 1.6rem;right: 3rem;
  • z-index: 199;
  • display: inline-block;
  • }

3.4 i18n

复制learn主题中的简体中文语言包zh-cn.toml(或新建)到docDock主题的i18n目录内:

  • [Search-placeholder]
  • other = "搜索..."
  • [Clear-History]
  • other = "清理历史记录"
  • [Attachments-label]
  • other = "附件"
  • [title-404]
  • other = "错误"
  • [message-404]
  • other = "哎哟。 看起来这个页面不存在 ¯\\_(ツ)_/¯。"
  • [Go-to-homepage]
  • other = "转到主页"
  • [Edit-this-page]
  • other = "编辑当前页"
  • [Shortcuts-Title]
  • other = "更多"
  • [Expand-title]
  • other = "展开"

三、页面内容

1、原型

原型是创建新页面内容(运行hugo new命令)时使用的模板,预先配置格式:例如md文件的扉页( front matter)、其它格式等。原型文件应该存放在archetypes目录内。

原型(archetypes/default.md)内的扉页貌似不能进行日期格式转换:

  • date属性只能是date: {{ .Date }},因为之后的日期格式转换基于此date属性。若date: {{.Date.Format "2006-01-02"}},将会触发错误:Error: Failed to process archetype file “default.md”:: template: default:3:19: executing “default” at <.Date.format>: can't evaluate field format in type string

1.1 default.md

default.md:将md文件构建为HTML的页面文件(type:缺省)。

  • ---
  • title: "{{ replace .Name "-" " " | title }}"
  • date: {{ .Date }}
  • author: "komantao"
  • LastModifierDisplayName: "komantao"
  • LastModifierEmail: komantao@hotmail.com
  • weight: 20
  • url: {{ replace .Dir "\\" "/" }}{{ replace .Name "-" " " | title }}.html
  • draft: false
  • description: "文章描述"
  • keywords: [keyword1, keyword2, keyword3]
  • tags: [标签1, 标签2]
  • categories: [分类1, 分类2]
  • ---
  • 首页描述。
  • <!--more-->
  • ## 一、概述
  • ## 参考资料
  • > - []()
  • > - []()
  • > - []()
  • ## 操作环境
  • > - 操作系统:Win 10
  • > -

1.2 chapter.md

chapter.md:将md文件构建为HTML的章节文件(type:chapter)。

  • +++
  • title = "{{ replace .Name "-" " " | title }}"
  • date = {{ .Date }}
  • weight = 5
  • chapter = true
  • +++
  • ### 自定义章节序号
  • # 自定义标题
  • 章节介绍

一定要设置chapter = truetype="chapter"才能生成章节文件。

1.3 slide.md

slide.md:将md文件构建为HTML的幻灯片文件(type:slide)。

  • +++
  • title = "Slide title"
  • type="slide"
  • theme = "league"
  • [revealOptions]
  • transition= 'concave'
  • controls= true
  • progress= true
  • history= true
  • center= true
  • +++
  • # Slide 1
  • ___
  • ## Slide 1.1
  • - Turn off alarm
  • - Get out of bed
  • ___
  • ## Slide 1.2
  • - Eat eggs
  • - Drink coffee
  • ---
  • # Slide 2
  • ___
  • ## Slide 2.1
  • - Eat spaghetti
  • - Drink wine
  • ___
  • ## Slide 2.2
  • - Get in bed
  • -

docDock主题提供了slide插件,必须配合插件才能生成HTML的幻灯片。

2、页面绑定

内容组织(Content Organization)指存放在content目录内的页面(pages),结构假设为:

  • ├─content # 网站源代码目录
  • | ├─_index.md # 网站主页(整个网站的简介)
  • | ├─posts # 一个名为posts的章节文件夹
  • | | ├─_index.md # 章节主页(整个章节的简介)
  • | | └─topic # 章节内的子页面内容目录(包含md文件和图片)
  • | | | ├─topic.md # 章节内的子页面内容(markdown文件)
  • | | | └─123.jpg # topic.md文件引用的本地图片

备注:内容文件若引用图片,Hugo建议将其与内容文件放在同一个目录内。

Hugo中的内容组织的管理依赖于Page Bundles(页面绑定)。Page Bundles包括:

  • Leaf Bundle(没有子节点)

  • Branch Bundle(home page、section、taxonomy terms、taxonomy list)

    • home page:网站主页

    • section:章节,在content目录内定义的子目录(多个子页面的集合)

      content目录下的第一级子目录都是一个section。如果想让任意一个子目录成为section,需要在目录下面定义_index.md文件。 所有的section构成一个section tree。

      • content
      • └── blog <-- Section, 因为是content的第一级子目录
      • ├── funny-cats
      • │ ├── mypost.md
      • │ └── kittens <-- Section, 因为包含_index.md
      • │ └── _index.md
      • └── tech <-- Section, 因为包含 _index.md
      • └── _index.md

      如果section tree 需要可导航,至少最底层的部分需要定义一个_index.md文件。

3、扉页

扉页( front matter)用来配置文章的标题、时间、链接、分类等元信息,提供给模板调用。可使用的格式有:yaml格式(默认格式,使用3个减号-)、toml格式(使用3个加号+)、json格式(使用大括号{})。除了网站主页外,其它内容文件都需要扉页来识别文件类型和编译文件。

  • ---
  • title: "xxx" # 文章标题
  • menuTitle: "xxx" # 文章标题在菜单栏中显示的名称
  • description: "xxx" # 文章描述
  • keywords: ["Hugo","keyword"] # 关键字描述
  • date: "2018-08-20" # 文章创建日期
  • tags: [ "tag1", "tag2"] # 自定义标签
  • categories: ["cat1","cat2"] # 自定义分类
  • weight: 20 # 自定义此页面在章节中的排序优先级(按照数字的正序排序)
  • disableToc: "false" # 若值为false(缺省值)时,此页面启用TOC
  • pre: "" # 自定义menu标题的前缀
  • post: "" # 自定义menu标题的后缀
  • chapter: false # 若值为true(缺省值)时,将此页面设置为章节(chapter)
  • hidden: false # 若值为true(缺省值)时,此页面在menu中隐藏
  • LastModifierDisplayName: "" # 自定义修改者的名称,显示在页脚中
  • LastModifierEmail: "" # 自定义修改者的Email,显示在页脚中
  • draft: false # true,表示草稿,Hugo将不渲染草稿
  • url: # 重置permalink,默认使用文件名
  • type: # type与layout参数将改变Hugo寻找该文章模板的顺序
  • layout:
  • ---
  • weight属性

    • 缺省时按照date属性的倒序排序(新日期排在前面)
    • 设置时,自定义此页面在章节中的排序(按照数字值的正序排序,数字小的排在前面,若数字值相同,则按照date属性的倒序排序)
  • pre属性

    在菜单栏中的标题前添加前缀:可为数字、文字、图标(Font Awesome库)等。

    • +++
    • title = "Github repo"
    • pre = "<i class='fab fa-github'></i> "
    • +++
  • menuTitle属性

    • 缺省时调用title属性作为此页面在menu中显示的名称
    • 设置时,自定义此页面在menu中显示的名称

4、主页页面

  1. 新建网站主页文件

    若未创建网站主页,运行hugo server时会提示创建一个网站主页:

    • Customize your own home page
    • The site is working. Don't forget to customize this homepage with your own. You typically have 3 choices :
    • 1. Create an _index.md document in content folder and fill it with Markdown content
    • 2. Create an index.html file in the static folder and fill the file with HTML content
    • 3. Configure your server to automatically redirect home page to one your documentation page

    使用hugo new XX.md命令在content目录内新建一个_index.md文件作为网站主页:

    • $ hugo new _index.md
    • E:\Hugo\sites\ebook\content\_index.md created
  2. 编写网站主页文件

    • 打开网站主页文件(content/_index.md)文件,编写内容
    • 通常不需要扉页,即使设置了,Hugo会忽略

5、章节页面

章节是包含其他子页面的页面,具有特殊的布局样式:通常仅包含章节序号、章节名称和本章节的简短摘要。

Hugo-theme-learn主题调用chapter.md原型文件来构建章节文件的扉页:

  1. 新建章节页面文件(同时新建了章节目录)

    • $ hugo new --kind chapter 个人网站/_index.md
    • E:\Hugo\sites\ebook\content\个人网站\_index.md created
  2. 编写章节主页文件

    打开章节主页文件(_index.md),编写内容(关键是设置chapter属性值为true):

    • +++
    • title = "blog" # 修改标题
    • date = 2019-11-28T13:48:56+08:00 # 修改日期
    • weight = 5 # 修改排序优先级别
    • chapter = true # true,表示此页面是章节页面
    • pre = "<b>X. </b>" # 修改在侧边栏显示的前缀
    • +++
    • ### 第二章 # 修改在章节页面显示的章节序号
    • # 个人网站 # 修改在章节页面显示的标题
    • 介绍制作个人静态网站的各种工具。 # 修改在章节页面显示的简短摘要

    网页的效果示例:

    image-20191128145802960

docDock主题没有提供chapter.md,但可直接使用learn主题的chapter.md

6、内容页面

在项目根目录中执行hugo new XX.md命令,会在content目录中自动创建XX.md文件:

  • $ hugo new 个人网站/hugo/"hugo.md"
  • E:\Hugo\sites\ebook\content\个人网站\hugo\hugo.md created
  • 文件名若有空格,则必需使用双引号括起;否则,可省略双引号

    不建议文件名含有空格!!!因为Hugo编译时,会将URL中文件的空格解析为-,从而导致本地图片链接解析失败。

  • 创建内容文件时应该使用子目录来实现文档分类

  • 若不指定--kind type,Hugo默认调用archetypes/default.md原型文件来构建内容页面文件的扉页

7、图片

7.1 引用图片

假设content目录的结构为:

  • ├─content # 网站源代码目录
  • | ├─_index.md # 网站主页(整个网站的简介)
  • | ├─posts # 一个名为posts的章节文件夹
  • | | ├─_index.md # 章节主页(整个章节的简介)
  • | | └─topic # 章节内的子页面内容目录(包含md文件和图片)
  • | | | ├─topic.md # 章节内的子页面内容(markdown文件)
  • | | | └─123.jpg # topic.md文件引用的本地图片

假设在md文件引用图片时使用Markdown语法为:

  • ![](123.jpg)

Hugo渲染时默认使用“Pretty URLs”,将md文件渲染为目录,在浏览器的地址栏中显示渲染后的路径(baseURL = “http://example.com/",渲染为本地web服务器http://localhost:1313/)。

开发者工具查看本地图片的渲染地址:

  • <a href="http://localhost:1313/posts/topic/topic/123.jpg" data-featherlight="image"><img src="topic/123.jpg" alt="123"></a>

发现图片的渲染路径比实际多了一个与文件名同名的目录。所以,本地图片渲染失败。

解决方法:基本思路是将“Pretty URLs”转换为“Ugly URLs”。

  • 使用“Pretty URLs”时

    • 方法1:使用“Pretty URLs”的文件命名方法

      md文件分目录存放,文件名统一命名为index.md或_index.md。

      • ├─content # 网站源代码目录
      • | ├─_index.md # 网站主页(整个网站的简介)
      • | ├─posts # 一个名为posts的章节文件夹
      • | | ├─_index.md # 章节主页(整个章节的简介)
      • | | └─topic # 章节内的子页面内容目录(包含md文件和图片)
      • | | | ├─_index.md # 章节内的子页面内容(markdown文件)
      • | | | └─123.jpg # 子页面引用的本地图片
      • md文件的扉页的title属性自动将目录名(示例为topic)识别为文件名
      • 本地图片和markdown文件位于同一目录内(目的是将路径简单化)
      • 缺点:一个目录只有一个md文件,文件名统一为index.md或_index.md
    • 不使用“Pretty URLs”的文件命名方法(md文件名使用个性化命名)时

      • ├─content # 网站源代码目录
      • | ├─_index.md # 网站主页(整个网站的简介)
      • | ├─posts # 一个名为posts的章节文件夹
      • | | ├─_index.md # 章节主页(整个章节的简介)
      • | | └─topic # 章节内的子页面内容目录(包含md文件和图片)
      • | | | ├─topic.md # 章节内的子页面内容(markdown文件)
      • | | | └─123.jpg # topic.md文件引用的本地图片
      • 方法2:在md文件的扉页内手动设置url参数

        在md文件的扉页中手动设置url为实际路径或“Ugly URLs”

        • url: posts/topic # 手动输入md文件的相对路径
        • url: posts/topic.html # 手动输入md文件的“Ugly URLs”

        缺点:每一个有图片的md文件都需要手动设置url参数。

      • 方法3:在原型文件(archetypes/default.md)设置变量自动获取url参数

        自动获取url的实际路径:

        • url: {{ .Dir }} # 自动提取md文件的相对路径
        • .Dir:一个页面变量,获取内容文件的路径(相对于content目录)

        在Windows平台下,路径的显示格式为:blog\。本地预览时没问题,发布到网站时,此格式就造成URL乱码(blog%5Chugo.html),导致读取图片失败。

        解决方法:

        • 手动改变格式为:blog/

        • 使用replace替换函数:

          • url: {{ replace .Dir "\\" "/" }}
          • \是一个转义符,因此使用\\将其转义为普通字符。转义后,将blog\替换为blog/
        • 缺点:一个目录内只能有一个md文件(否则,多个md文件将会渲染为同一个目录,Hugo只能选择一个)

        自动获取“Ugly URLs”:

        • url: {{ replace .Dir "\\" "/" }}{{ replace .Name "-" " " | title }}.html
        • 此方法最完美:
          • 既不破坏Hugo默认的“Pretty URLs”设置
          • 指定的md文件又能实现“Ugly URLs”:一个目录内可以有多个md文件,md文件与引用图片可以在不同目录内
          • 解决了Windows平台下的路径转换
    • 方法4:在网站配置文件config.toml中设置

      • [permalinks]
      • blog = "/:sections/:slug/" # blog是某个指定的目录名
      • 此方法不可行(只是演示Permalink(固定链接)的用法),因为不能转换为“Ugly URLs”,渲染路径依然是“Pretty URLs”
    • 方法5:愚蠢的方法,图片复制为2份,分别为Markdown语法和Hugo渲染所用

      • 若不设置relativeURLs(默认),静态资源的路径相对于static目录

        1. md文件和本地图片在同一级目录内,目的是将路径简单化

        2. md文件中引用图片时使用Markdown语法

          • ![](123.jpg)
        3. 将本地图片复制一份到static目录,按照“Pretty URLs”格式构建路径

          例如md文件在content目录的路径为content/posts/topic.md,则其引用图片在static目录的路径为static/posts/topic/123.jpg

      • 若设置relativeURLs,静态资源的路径相对于content目录

        1. md文件和本地图片在同一级目录内,目的是将路径简单化

        2. md文件中引用图片时使用Markdown语法

          • ![](123.jpg)
        3. 将本地图片复制一份到content目录,按照“Pretty URLs”格式构建路径

          例如md文件在content目录的路径为content/posts/topic.md,则其引用图片在content目录的路径为content/posts/topic/123.jpg

        4. 在网站配置文件config.toml中设置

          • relativeURLs = false => relativeURLs = true
  • 使用“Ugly URLs”时

    静态资源的路径相对于content目录,且与Markdown语法使用的路径完全一致。

    1. md文件和本地图片在同一级目录内,目的是将路径简单化

    2. md文件中引用图片时使用Markdown语法

      • ![](123.jpg)
    3. 在网站配置文件config.toml中设置

      • uglyurls = true

      使用“Ugly URLs”渲染content目录后,将md文件渲染为html文件:

      • content/posts/_index.md => example.com/posts/index.html
      • content/posts/topic/topic.md => example.com/posts/topic/topic.html
    4. 此方法破坏了url默认设置(“Pretty URLs”),因此需要修改url渲染失败的功能

      • 搜索config.toml

        • [[menu.shortcuts]]
        • name = "<i class='fas fa-align-justify'></i> 分类"
        • url = "/categories.html" # “Pretty URLs”时,url = "/categories"
        • weight = 12
        • [[menu.shortcuts]]
        • name = "<i class='fas fa-bookmark'></i> 标签"
        • url = "/tags.html" # “Pretty URLs”时,url = "/tags"
        • weight = 13
      • 搜索partials

        hugo-theme-learn主题在页面上显示的标签导航使用“Pretty URLs”:

        image-20191204125335380

        themes/hugo-theme-learn/layouts/partials/header.html文件中禁用此功能:

        • <!-- # 新增,将其转换为注释
        • <div id="head-tags">
        • {{ partial "tags.html" . }}
        • </div>
        • --> # 新增

        或将其转换为.html(“Ugly URLs”)。(不懂修改模板)

7.2 调整图片

  1. 调整图片大小

    添加图像的HTTP参数((width、height),值为CSS值(默认为auto):

    • ![Minion](https://octodex.github.com/images/minion.png?height=50px&width=300px)
  2. 调整图片显示效果

    添加一个CSS类(classes),值为shadow、border等:

    • ![Minion](https://octodex.github.com/images/minion.png?classes=border,shadow)

四、模板

Hugo以go语言的html/template库作为模版引擎,将内容通过template渲染成html,模版作为内容和显示视图之间的桥梁。

1、模板类型

Hugo有一套模版查找机制,如果找不到与内容完全匹配的模板,它将搜索上一级。直到找到匹配的模板。如果找不到模板,将使用默认模板。

hugo有三种类型的模版:

  1. Single Template:用于渲染页面内容

  2. List Template:用于渲染一组相关内容

    一个站点下所有内容或一个目录下的内容(section listings、home page、taxonomy lists、taxonomy terms)。homepage(_index.md),是一个特殊类型的list template,homepage是一个站点所有内容的入口。

  3. partial Template:可理解为模版级别的组件,可以被其他模版引用

    通常存放在项目根目录(或主题目录)内的layouts/partial目录。

页面模版查询规则:判断页面是single page还是list page:

  • single page:选择模版themes/主题名/layouts/_default/single.html
  • list page,选择模版themes/主题名/layouts/_default//list.html

Output Format:

  • 根据输出格式的名称和后缀,选择匹配的模版。例如输出格式是rss,后缀是.html,首先看有没有匹配的index.rss.html格式的模版

Language:

  • 根据站点设置的语言选择匹配的模版,比如,站点的语言为fr,模版匹配的优先级是:index.fr.amp.html > index.amp.html > index.fr.html

Layout:

  • 可以在页面头部设置front matter:layout,设置页面用指定的模版进行渲染,例如,页面在目录posts(默认section)下面,layout=custom,查找规则如下:

    • layouts/posts/custom.html
    • layouts/posts/single.html
    • layouts/_default/custom.html
    • layouts/_default/single.html

type:

  • 如果在页面的头部设置了属性type属性,例如type=event,查找规则如下:

    • layouts/event/custom.html
    • layouts/event/single.html
    • layouts/events/single.html
    • layouts/_default/single.html

2、模板语法

block:

  • 在父模板中通过{{block “xxx”}}定义一个块

  • 在子模块中通过{{define “xxx”}}定义的内容进行替换

模板引用:

  • 方法一:partial(推荐使用)

    引入定义的局部模板(位置在themes/layouts/partialslayouts/partials目录内):

    • {{ partial "chrome/header.html" . }}
  • 方法二:template

    在一些比较老的版本中用于引入定义的局部模版,现在在内部模版中仍然使用。

    • {{- xxx -}}
    • -用于去除空格

      {{- xxx}用于去除{{- 前边的空格、{{ xxx -}用于去除-}}后边的空格、{{- xxx -}}用于去除两边的空格。

Paginator:

  • .Paginator主要用来构建菜单,只能在homePage、listPage中使用

    • {{ range .Paginator.Pages }}
    • {{ .Title }}
    • {{ end }}

简码:

  • 简码(shortcodes)相当于一些自定义模版,通过在md文档中引用,生成代码片段,类似于一些js框架中的组件

  • 简码必须在themes/layouts/partials或者layouts/partials目录内定义

  • 简码在模版文件中引用是无效的,只能在content目录下的md文件中引用

  • 引用方式

    • {{% msshortcodes params1="xxx" %}}**this** is a text{{% /msshortcodes %}}
    • {{< msshortcodes params1="xxx" >}} **Yeahhh !** is a text {{< /msshortcodes >}}
    • %:代表短代码中的内容使用Markdown语法,需要进一步渲染
    • <:代表短代码中间的内容使用HTML语法,不需要渲染

taxonomy:

参阅:Hugo中定制Taxonomy页面

  • Hugo中通过taxonomy来实现对内容的分组。taxonomy需要在站点配置文件中定义:

    • [taxonomies]
    • category = "categories"
    • tag = "tags"
    • series = "series"
    • 默认情况下,Hugo提供了category、tag两个分类,不需要用户在配置文件中定义,但如果还有其他的taxonomy定义,则默认的tag、category也需要定义
    • 使用方式
      1. 在站点配置文件中添加taxonomy,例如:series
      2. 定义taxonomy list template,例如:layouts/taxonomy/series.html
      3. 在内容文件的front matter中设置term;例如:series = [“s1”,“s2”]
      4. 访问taxonomy列表,例如:localhost:1313/series/s1

变量:

  • Hugo提供了很多不同类型变量用于创建模版,构建站点

Site:

  • 大部分站点变量定义在站点配置文件中(config.[yaml|toml|json] )

    • .Site.Menus:站点下的所有菜单
    • .Site.Pages:站点下的所有页面
    • .Site.Params: 站点下的参数

Page:

  • 页面级参数都定义在页面头部的front matter中,例如:

    • title = "Hugo"
    • date = 2018-08-13T18:29:20+08:00
    • description = ""
    • draft = false
    • weight = 10
  • 使用方式

    • {{ .Params.xxx }} 或者是 {{ .Site.Params.xxx }}

五、简码

简码(shortcode)是内容(content)文件中的简单代码段,调用内置或自定义模板,在Markdown文件中使用HTML语法实现某些功能。

Hugo使用Markdown是因为其内容格式简单。但是,Markdown有其不足,有时被迫在Markdown文件中使用纯HTML来扩展用法。但这与Markdown语法的简单性相矛盾。为了避免这种限制,Hugo创建了简码

简码不能用于模板文件。如果需要在模板中插入简码,则很可能需要 partial template

除了Markdown更简洁外,简码可以随时更新以反映新的类、技术或标准。在网站生成时,Hugo简码将轻松合并到您的更改中。您避免了可能很复杂的搜索和替换操作。

Hugo通过简码扩展了Markdown用法(在不破坏Markdown语法简单性的基础上使用HTML语法)。Typora编辑器不能识别简码,即只能通过Hugo渲染后在HTML网页上才能浏览效果。

1、预设简码

简码在Markdown文件中的调用语法:

  • # 分隔符使用% %,内含的源代码使用Markdown语法(可被渲染,**World**显示为粗体)
  • # 从Hugo_V_0.55开始,%作为最外层的分隔符,某些简码不能使用%分隔符,触发错误raw HTML omitted
  • {{% shortcodename parameters %}}Hello **World**{{% /shortcodename %}}
  • # 分隔符使用< >,内含的源代码使用HTML语法(不可被渲染,**World**显示为**World**)
  • {{< shortcodename parameters >}}Hello **World**{{< /shortcodename >}}
  • shortcodename:简码文件(shortcodename.html)的文件名,需要事先定义

  • parameters:参数

  • 简码的优先级高于代码块

    即使将简码放入代码内,Hugo依然识别出简码。若简码文件没有事先定义,Hugo渲染时会触发错误:failed to extract shortcode: template for shortcode “shortcodename” not found。

  • 若想运行简码,简码的源代码不应该放入代码块内

    有的简码可在代码块内运行,有的不行。

  • 若想在代码块内放入简码的源代码,需要破坏简码的语法

    例如:在{{之间添加空格或添加注释符号/* */;使用时,删除增加的部分。

  • 简码的分隔符有% %(Hugo_V_0.55后,作为最外层的分隔符)和< >

    分隔符和大括号之间不能有空格分隔。

  • 简码参数(shortcodename、parameters)之间、分隔符和简码参数之间由空格分隔

    若parameters包含空格,则应该使用引号括起,格式为:name="value"

示例:引用Hugo的预设简码figure,构建HTML5的figure标签显示图片

  • { {< figure src="/images/风车.gif" title="网站logo" >}}

显示效果(经过Hugo渲染后,在HTML网页才能看到效果):

网站logo

简码在网页HTML结构中显示的标签为:

  • <figure>
  • <img src="../images/风车.gif" style="cursor: pointer;"> <figcaption>
  • <h4>网站logo</h4>
  • </figcaption>
  • </figure>

Hugo-theme-learn主题的简码:https://learn.netlify.com/en/shortcodes/。

Hugo-theme-docDock主题的简码:https://docdock.netlify.com/shortcodes。

  • alert:突出显示页面中的信息
  • attachments:显示页面附件文件的列表
  • button:在页面中显示可操作的按钮
  • children:列出页面的子页面
  • excerpt:标记页面内容的一部分以供重复使用
  • excerpt-include:显示另一页面中“摘录”(即一部分)内容
  • expand:在页面上显示文本的可打开/折叠部分
  • icon:显示图标
  • mermaid:生成图表(diagram)和流程图(flowchart),其方式与Markdown语法类似
  • notice:构建页面的免责声明
  • panel:突出显示信息或将其放在框中,在文本周围创建一个彩色框
  • revealjs:将内容显示为Reveal.js幻灯片
  • siteparam:获取页面中站点参数变量的值(用于config.toml

2、新建简码

新建简码时,将模板(shortcodename.html文件)放入项目根目录或主题的layouts/shortcodes目录中,Hugo渲染时,会以此目录作为简码的根目录读取简码的HTML文件。

示例:创建一个折叠代码行的简码

  1. 新建简码的HTML文件,假设命名为collapsible.html

    • <details>
    • <summary style="background-color:#f5f5f5;border:1px solid #ccc;padding:5px;">
    • {{ with .Get 0}}{{.}}{{else}}click to expand{{ end }}
    • </summary>
    • {{.Inner}}
    • </details>
    • 设置的功能非常简单,只是简单的折叠行,尚未实现折叠代码块的功能
  2. 在Markdown文件中使用简码collapsible

    • { {< collapsible "折叠" >}}
    • 折叠行的代码内容1<br/.>
    • 折叠行的代码内容2
    • { {< /collapsible >}}

    显示的效果(经过Hugo渲染后,在HTML网页才能看到效果):

    折叠 折叠行的代码内容1
    折叠行的代码内容2

六、编译

在项目根目录中执行hugo server 命令调用Hugo内置的本地web服务器调试预览博客:

  • --theme:指定主题
  • --watch:修改文件后自动刷新浏览器(v0.15版本后,缺省此参数也可自动刷新)
  • --buildDrafts:编译草稿文件(扉页中的draft值为true)
  • $ hugo server --theme=hugo-theme-learn --buildDrafts --watch
  • Building sites … WARN 2019/11/27 16:09:27 .File.UniqueID on zero object. Wrap it in if or with: {{ with .File }}{{ .UniqueID }}{{ end }}
  • | EN
  • +------------------+----+
  • Pages | 10
  • Paginator pages | 0
  • Non-page files | 1
  • Static files | 77
  • Processed images | 0
  • Aliases | 0
  • Sitemaps | 1
  • Cleaned | 0
  • Total in 75 ms
  • Watching for changes in E:\Hugo\sites\ebook\{archetypes,content,data,layouts,static,themes}
  • Watching for config changes in E:\Hugo\sites\ebook\config.toml
  • Environment: "development"
  • Serving pages from memory
  • Running in Fast Render Mode. For full rebuilds on change: hugo server --disableFastRender
  • Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
  • Press Ctrl+C to stop

七、部署

实现:源代码推送到源代码仓库后,自动部署到多个不同的发布网站。

将博客部署到:

  • Pages网站

    Git托管平台免费提供的Pages服务,缺点是必须公开仓库(别人可轻易获取代码)。

    • GitHub Pages

      公开GitHub的发布仓库后,就能免费使用GitHub Pages服务。

      服务器在国外,国内访问速度不稳定。而且,GitHub Pages屏蔽了百度爬虫,百度无法爬取GitHub Pages网页。

    • Gitee Pages

      Gitee(国内的Git免费托管平台)提供的免费Pages服务(发布仓库可私有,但需要手机验证),服务器在国内,国内访问速度快,但受各种政策影响体验。

  • Netlify

    Netlify是GitHub Pages + Travis CI的完美结合。Netlify在线克隆GitHub源代码仓库(可私有),持续集成和自动部署(Travis CI功能)到其提供的免费网站(Pages服务),然后还额外提供了众多的免费服务。

    缺点是服务器在国外,国内访问速度不稳定,而且不能查看发布仓库。

  • 个人网站

    个人在域名提供商(例如freenom)购买域名。在国内CDN提供商注册域名需要公安局备案。

1、代码安全

一次提交推送到多个仓库(目的纯粹是为了源代码安全)。

为了源代码安全,应该将源代码推送到不同的git代码仓库(例如GitHub和Gitee):

  • 方法一:推送到GitHub后,在Gitee导入GitHub仓库

    手动操作:新建仓库 — 导入已有仓库 — 输入已有仓库的git地址。

  • 方法二:手动多次推送到不同仓库

    每一个仓库都手动推送一次:

    • git remote add origin <仓库的git地址> # 关联仓库
    • git push -u origin master # 推送到仓库
  • 方法三:将一个提交一次性推送到不同仓库

    将多个地址添加到origin库后,使用git push origin master 一次性push到多个仓库:

    • git remote add origin <仓库1的git地址> # 关联仓库1,别名为origin
    • git remote set-url --add origin <仓库2的git地址> # origin仓库添加仓库2
    • git remote set-url --add origin <仓库3的git地址> # origin仓库添加仓库3,origin仓库共指向3个不同仓库
    • git push -u origin master # 推送到3个不同的仓库

2、手动部署

以GitHub为例。

  1. 在GitHub创建一个源码仓库

    仓库名随意,权限可为私有,用来存储博客的源代码(pbulic目录外的所有文件)。若不需要对源代码进行版本管理,可不需要创建源码仓库。

  2. 在GitHub创建一个发布仓库

    权限公开,才能开启GitHub Pages服务,用来存储博客的发布内容(pbulic目录)。

    • 使用用户仓库

      命名为<username>.github.io,GitHub Pages的网址为http://username.github.io/。一个帐户只能有一个用户仓库,优点是网址相对简单。

    • 使用项目仓库

      命名随意,GitHub Pages的网址为http://username.github.io/xxx。一个帐户可以有多个项目仓库。

  3. Hugo生成发布内容(public目录)

    在项目根目录内运行hugo --theme=<themename>命令(若在config.toml已配置了theme选项,可直接运行hugo命令),将发布内容生成到public目录。

    • $ hugo
    • Building sites … WARN 2020/01/07 21:30:32 .File.BaseFileName on zero object. Wrap it in if or with: {{ with .File }}{{ .BaseFileName }}{{ end }}
    • | EN
    • +------------------+-----+
    • Pages | 60
    • Paginator pages | 0
    • Non-page files | 89
    • Static files | 211
    • Processed images | 0
    • Aliases | 17
    • Sitemaps | 1
    • Cleaned | 0
    • Total in 833 ms
  4. public目录内创建本地仓库

    • $ cd public # 进入public目录
    • $ git init # 新建本地仓库
    • $ git add . # 暂存当前目录(public目录)
    • $ git commit -m "first commit" # 提交
  5. pubilc目录推送到GitHub的发布仓库

    • $ git remote add origin git@github.com:username/username.github.io.git
    • $ git push -u origin master
  6. GitHub根据发布仓库自动创建GitHub Pages网站,浏览器输入网址(https://username.github.io/)就能访问博客

3、Travis CI

手动部署(Manual Deployment)是一个重复性劳动,既繁琐又耗时且容易出错。因为部署流程基本固定,所以应该交由CI/CD工具自动完成。

编写代码只是软件开发的一小部分,更多时间往往花在构建(build)和测试(test)上。为了提高软件开发效率,持续集成、持续交付、持续部署工具层出不穷。在GitHub市场上提供了众多的持续集成服务提供商(工具)。

  • 持续集成(Continuous Integration)

    是一个开发行为,强调开发人员提交新代码后,立刻进行构建、(单元)测试。根据测试结果,即时发现问题,即时修复。

  • 持续交付(Continuous Delivery)

    在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的“类生产环境”(production-like environments)中。例如,完成单元测试后,可以把代码部署到连接数据库的Staging环境中进行更多的测试。若没有问题,可以继续手动部署到生产环境中。

  • 持续部署(Continuous Deployment)

    在持续交付的基础上,将部署到生产环境的过程自动化。

Travis CI是一个使用Ruby语言开发、在线托管、开源的分布式持续集成服务提供商,是CI工具中市场份额最大的一个。Travis CI目前有两个官网:

  • Travis CI:旧平台(已逐步放弃),只对开源项目(公开仓库)免费
  • Travis Pro:新平台,对开源项目和私有项目(私有仓库)免费

通过Travis CI部署Hugo或者Hexo博客在配置时可能麻烦一点,但配置好后非常方便好用,特别是对于Hugo这种没有部署插件的静态网站生成器。

3.1 部署到GitHub Pages

GitHub使用Travis CI非常简单,因为GitHub的token具有推送代码的权限,一切都能在线操作。

3.1.1 两个远程仓库

缺点:公开了发布代码(源代码可私有)。

参阅:使用Travis CI自动部署Hugo博客

  1. GitHub创建2个远程仓库

    • 仓库A:存放Hugo的输入文件(public目录外的所有文件)

      命名随意,权限可为私有。

    • 仓库B:存放博客发布文件(public目录)

      使用用户仓库(<username>.github.io),权限公开,开启GitHub Pages服务。

  2. GitHub生成个人访问令牌(Personal Access Token)

    Travis CI自动部署时,需要push内容到仓库的某个分支,而访问GitHub仓库需要用户授权,授权方式就是用户提供访问令牌给Travis CI。

    在GitHub生成token(路径:帐户Settings — Developer settings — Personal access tokens — Generate new token),至少需要勾选 public_repo权限。建议:勾选repo上的所有项目,别的项目一个都不要选。

  3. 配置Travis CI Pro

    1. 登录(注册)Travis CI Pro

      进入Travis CI官网,登录(注册)Travis CI:

      image-20200114143054489

      首次登录(注册)时,Travis CI请求关联GitHub:

      image-20200114143219508

    2. 激活帐户,选择源代码仓库

      登录后,进入getting_started页面,点击帐户(页面上方的导航栏最右侧登录头像)内的“Settings”:

      image-20200114144017361

      进入个人帐户(MY ACCOUNT)页面:

      image-20200114144415406

      首次使用时,激活“GitHub Apps Integration”。

      “GitHub Apps Integration”支持私有和公开仓库,与GitHub交互时提供增强的安全性。

      点击“Activate”后,弹出页面:

      image-20200114145037486

      • 选择“All repositories”,表示选择GitHub帐户中的所有仓库(包含未来新建)
      • 选择“Only select repositories”,表示只选择GitHub帐户中的指定仓库
      • 点击“Approve & Install”后,可在GitHub(帐户Settings — Applications — Install GitHub Apps)中查看安装结果或重新配置
    3. 同步帐户

      “GitHub Apps Integration”激活完毕后,Travis返回“MY ACCOUNT”页面,并自动(或点击“Sync account”)显示帐户内的仓库。

      image-20200114150416516

    4. 激活源代码仓库

      指定帐户内的某个仓库为源代码仓库。Travis将根据此激活仓库的提交自动部署到博客网站。点击上图中的仓库列表中某一个,即可进入仓库界面:

      image-20200114160144369

      仓库的功能菜单项有:

      • Current:仓库的当前状态

        可查看最新构建的日志(log):

        • hugo命令成功运行时显示:The command “hugo” exited with 0.
        • build命令成功运行时显示:Done. Your build exited with 0.
      • Build History:仓库的构建历史

      • Settings:仓库设置,部署触发条件和添加环境变量(Personal Access Token)

        • 勾选触发条件

          General、Auto Cancellation、Config Import等选项,使用默认值即可。

        • 设置环境变量(Environment Variables)

          在“Environment Variables”中输入token信息后,点击Add按钮: image-20200107164339086

          • NAME:名称任意,例如GITHUB_TOKEN
          • VALUE:在GitHub申请到的Token的值
          • BRANCH:默认值(all branches)
      • 设置好的变量在配置文件中以 ${变量名}来引用

    • Trigger build:手动触发构建

      当源代码仓库已有提交时,可手动触发构建。日常使用时,可忽略此步骤。

      弹出界面使用默认值即可:

      image-20200113151506405

  4. 新建Travis配置文件

    配置文件(.travis.yml)告诉Travis CI如何部署博客,一个完整的构建生命周期为:

    • Install apt addons # (可选)
    • Install cache components # (可选)
    • before_install # 安装依赖前
    • install # 安装依赖
    • before_script # 执行脚本前
    • script # 执行脚本
    • before_cache(for cleaning up cache) # (可选)
    • after_success or after_failure # 执行脚本成功(失败)后
    • before_deploy # (可选),部署前
    • deploy # (可选),部署
    • after_deploy # (可选),部署后
    • after_script # 执行脚本后

    Travis CI的一次构建分为两个阶段:

    • install(安装)阶段:安装所需的依赖项,例如hugo框架
    • script(脚本)阶段:运行构建脚本所需的命令,例如hugo命令、git命令

    在本地项目根目录中新建Travis配置文件(.travis.yml),此文件应该上传到仓库A。如果配置文件不在仓库A中,或者不是有效的YAML,Travis CI将无法构建项目。

    使用Python语言(Travis指定语言示例 ,Python耗时比Golang少)配置Travis环境。

    • language: python # Travis的语言环境为Python
    • python:
    • - "3.7" # python版本指定为3.7
    • branches: # 分支白名单限制
    • only:
    • - master # 只有master分支的提交才会触发构建
    • env: # 设置环境变量
    • global:
    • - GH_REF: github.com/username/username.github.io.git # 发布仓库的Git地址(使用HTTPS协议)
    • install: # 安装依赖项
    • - wget https://github.com/gohugoio/hugo/releases/download/v0.62.2/hugo_0.62.2_Linux-64bit.deb # 手动下载Hugo指定版本
    • - sudo dpkg -i hugo*.deb # 安装Hugo版本
    • script:
    • - hugo # 运行hugo命令,生成发布内容(public目录)
    • # 将博客发布内容推送到GitHub的发布仓库(不是源代码仓库)
    • after_script:
    • - cd ./public
    • - git init
    • - git config user.name "xxx"
    • - git config user.email "xxx@xxx.com"
    • - git add .
    • - git commit -m "Update Blog By TravisCI With Build $TRAVIS_BUILD_NUMBER"
    • - git push --force --quiet "https://$GITHUB_TOKEN@${GH_REF}" master:master
    • # 将博客发布内容推送到GitHub的源代码仓库的另一个分支(需要时,去掉注释,即#号)
    • # deploy:
    • # provider: pages # 部署到GitHub Pages网站
    • # skip-cleanup: true # 必须为true,否则Travis会删除在构建期间创建的所有文件(即删除了计划上传的文件)
    • # local-dir: public # 要推送到GitHub Pages的目录,可以指定为当前目录的绝对路径或相对路径
    • # on:
    • # branch: master # 博客源代码所在分支
    • # target-branch: xxx # 将local-dir强制推送到哪个分支(自定义,名称不能与源代码分支名相同),默认为gh-pages
    • # github-token: $GITHUB_TOKEN # $GITHUB_TOKEN是一个变量:名称是Travis定义名称,值是GitHub的personal access token的值
    • # fqdn: xxx # 使用自定义域名
    • # verbose: true # true,表示显示Travis的log
    • # keep-history: true # true,表示保持target-branch分支的提交记录
    • Travis是在线构建,不占用本地空间
    • 若仓库B的Git地址(GH_REF变量)填写错误时,不提示错误且不会上传到仓库B
    • 部署(deploy)环节的内容:是将发布内容上传到源代码仓库(仓库A)的另一个分支(target-branch名称不能与源代码分支名相同,否则覆盖源代码)
  5. 本地仓库

    在本地项目根目录中新建一个本地仓库存放Hugo的输入文件(public目录外的所有文件)。

    1. 创建忽略文件

      本地仓库不应该包含public目录(Travis会在线生成,可忽略)、themes目录(若自定义了主题,则不能忽略)和resources目录(可忽略)。

      忽略文件(.gitignore)内容假设为:

      • public/
      • resources/
    2. 当前项目(假设为book)创建本地仓库并推送到GitHub的仓库A

      • $ git init
      • Initialized empty Git repository in E:/Hugo/sites/book/.git/
      • $ git add .
      • $ git commit -m "generator code"
      • $ git remote add github git@github.com:username/xxx.git
      • $ git push -u github master
  6. 持续集成和自动部署

    若Travis设置了“提交触发build”,本地仓库的每次推送到仓库A,Travis CI都会得到提示,然后根据仓库A中的配置文件(.travis.yml)自动进行部署,实现了博客的自动持续集成(仓库B根据仓库A的内容自动更新,GitHub Pages网站根据仓库B的内容自动更新)。

    简单一句话:只需要将写好的文章推送到GitHub的仓库A,不需要编译、不需要推送到仓库B、 甚至连Hugo都可以不安装(假设使用主题没有自定义)。

3.1.2 一个远程仓库

缺点:源代码和发布代码都公开了。

方法一:参阅利用Travis CI和Hugo將Blog自動部署到Github Pages

  1. 在GitHub创建一个远程仓库

    存放Hugo的输入文件和博客发布文件。命名为<username>.github.io,权限为公开,开启GitHub Pages服务。

  2. GitHub生成个人访问令牌(TOKEN)和配置Travis CI

    步骤同上。

  3. 新建Travis CI的配置文件(.travis.yml

    • # https://docs.travis-ci.com/user/deployment/pages/
    • # https://docs.travis-ci.com/user/reference/xenial/
    • # https://docs.travis-ci.com/user/languages/python/
    • # https://docs.travis-ci.com/user/customizing-the-build/
    • dist: xenial
    • language: python
    • python:
    • - "3.7"
    • # install - install any dependencies required
    • install:
    • # install latest release version
    • # Github may forbid request from travis container, so use tor proxy
    • # - curl -fsL --socks5-hostname 127.0.0.1:9050 https://api.github.com/repos/gohugoio/hugo/releases/latest | sed -r -n '/browser_download_url/{/Linux-64bit.deb/{s@[^:]*:[[:space:]]*"([^"]*)".*@\1@g;p;q}}' | xargs wget
    • - wget https://github.com/gohugoio/hugo/releases/download/v0.62.2/hugo_0.62.2_Linux-64bit.deb
    • - sudo dpkg -i hugo*.deb
    • # script - run the build script
    • script:
    • - hugo
    • deploy:
    • provider: pages
    • skip-cleanup: true
    • github-token: $token
    • email:
    • name:
    • verbose: true
    • keep-history: true
    • local-dir: public
    • target_branch: master # branch contains blog content
    • on:
    • branch: code # branch contains Hugo generator code
  4. 本地仓库

    1. 创建忽略文件

      本地仓库不应该包含public目录(Hugo本地编译时产生)、themes目录(存放主题)和resources目录(由主题产生)。

      忽略文件(.gitignore)内容假设为:

      • public/
      • resources/
    2. 当前项目(假设为book)创建本地仓库

      • $ git init
      • Initialized empty Git repository in E:/Hugo/sites/book/.git/
    3. 分支A(code分支)

      命名为code,存放Hugo的输入文件(博客工程文件,即public目录外的文件)。

      • $ git checkout -b code
      • # 在code分支
      • $ git add .
      • $ git commit -m "generator code"
      • $ git remote add github git@github.com:username/username.github.io.git
      • $ git push -u github code
    4. 分支B(master分支)

      命名为master,博客发布文件(即public目录)存放在master分支。

      • # 在code分支
      • $ hugo # 生成public目录
      • $ HUGO_TEMP_DIR=$(mktemp -d) # 设置临时变量
      • $ cp -R public/* "$HUGO_TEMP_DIR" # public目录复制到临时变量
      • $ git checkout --orphan master # 创建master分支
      • # 在master分支
      • $ rm .git/index # 清除暂存区
      • $ git clean -fdx # 清除未跟踪文件,当前目录只剩下.git目录
      • $ cp -R "$HUGO_TEMP_DIR"/. . # public目录内容复制到当前目录
      • $ git add .
      • $ git commit -m 'initial blog content'
      • $ git push -u github master
      • $ [[ -d "$HUGO_TEMP_DIR" ]] && rm -rf "$HUGO_TEMP_DIR" # 删除临时变量
      • # 切换到code分支,以后应该只在code分支
      • $ git checkout code
  5. 持续集成

    如果上述步骤中设置了“提交触发build”,本地仓库的每次推送到code分支,Travis CI会自动进行部署,将上传的博客内容(code分支)更新到仓库的master分支中,实现了博客的持续集成(GitHub Pages网站根据master分支内容自动更新),不再需要关心travis状态。

方法二:

  • 方法一略显复杂,简捷方法是在两个GitHub仓库方法中的Travis配置文件(.travis.yml)中启用“deploy”配置,就能实现在一个仓库内实现源代码分支和发布分支。

3.2 部署到Gitee Pages

GitHub Pages和Netlify的服务器在国外,国内访问速度慢且稳定性差。解决这一问题的最优解是购买个人域名使用CDN。对于不想购买个人域名的人来说,使用Gitee Pages(码云的Pages服务)是当前的最优解决方案。

码云仓库(可为私有,GitHub的必需公开)开启Pages服务需要绑定手机号(不需要在公安局备案)。码云是国内的Git托管平台,所以在国内访问速度超快(对比GitHub)且稳定。仓库有更新时,Gitee Pages貌似不会自动更新,需要手动更新(GitHub Pages是自动更新)。

Gitee使用Travis CI比较麻烦,因为Gitee的token没有推送代码的权限,所以需要下载Travis CI到本地,然后在本地加密私钥文件或密码,最后使用加密后的密码push。

参阅:travis官网文档手摸手教你搭建Travis CI持续集成和自动化部署使用travis-ci自动部署hexo博客Hexo集成Travis CI

使用Travis CI部署到Gitee的过程:

  1. 源代码仓库是GitHub仓库

    因为Travis CI只能使用GitHub帐户注册,因此只能绑定GitHub仓库为源代码仓库。

  2. 发布仓库是Gitee仓库

    修改Travis配置文件(.travis.yml)中的GH_REF变量(发布仓库,为了区分不同的仓库,名称可自定义命名)的值为Gitee仓库的git地址:

    • env: # 设置环境变量
    • global:
    • - GH_REF: github.com/username/username.github.io.git # GitHub发布仓库的Git地址(使用HTTPS协议)
    • #- GE_REF: gitee.com/username/username.git # Gitee发布仓库的Git地址(使用HTTPS协议)
  3. 自动验证密码

    Gitee的token没有推送代码的权限,所以此命令失效:

    • git push --force --quiet "https://$Gitee_TOKEN@${GE_REF}" master:master # 强制推送到Gitee发布仓库

    改用其它方式验证密码:

    1. 使用https协议,显式添加用户名、密码进行推送

      • git push --force --quiet "https://用户名:密码@${GE_REF}" master:master

      缺点:彻底暴露Gitee帐户的用户名和密码(即使GitHub仓库是私有),风险极大。

    2. 使用ssh协议,使用私钥文件免密推送

      • git push --force --quiet "git@gitee.com:用户名/用户名.git" master:master

      缺点:需要将本地的私钥文件推送到GitHub仓库,风险极大。

    3. 通过加密私钥文件或密码

  4. 具体的Travis配置文件(.travis.yml)与GitHub的基本一致

3.3 Travis加密

无论是使用token(GitHub,token在Travis CI中显式显示),还是显式使用密码或上传或ssh私钥(Gitee),即使源代码仓库是私有的,也是存在极大风险。

Travis提供了加密服务,可以对密码或者私钥文件进行加密。

  1. 本地安装Ruby

    Travis客户端使用Ruby语言编写,所以先安装Ruby。(参阅:Ruby 安装 - Windows

    不建议安装Ruby for Windows。因为Windows不支持openssl验证,导致Travis对密钥文件解密时触发错误:The command “openssl xxx -in id_rsa.enc -out ~/.ssh/id_rsa -d” failed and exited with 1 during。

    验证Ruby和gem(安装Ruby时自动安装)是否安装成功:

    • $ ruby -v
    • ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x64-mingw32]
    • $ gem -v
    • 3.1.2
  2. 本地安装Travis客户端

    • $ gem install travis

    验证是否安装成功:

    • $ travis -v
    • D:/Program/Ruby/lib/ruby/gems/2.7.0/gems/highline-1.7.10/lib/highline.rb:624: warning: Using the last argument as keyword parameters is deprecated
    • 1.8.10
  3. 关联GitHub源代码仓库

    (克隆GitHub源代码仓库)进入本地工程目录,输入命令:

    • $ travis login --auto --pro
    • Username:xxx # 输入GitHub帐户名
    • Password for xxx: xxx # 输入GitHub帐户密码
    • Successfully logged in as xxx!
    • –pro:绑定travis-ci.com,缺省时绑定travis-ci.org
  4. 加密

    1. 加密本地系统的私钥文件(~/.ssh/id_rsa文件),使用SSH协议push

      • $ travis encrypt-file ~/.ssh/id_rsa --add
      • # 下面是命令行打印的日志
      • Detected repository as xxx/xxx, is this correct? |yes| yes
      • encrypting ~/.ssh/id_rsa for xxx/xxx
      • storing result as id_rsa.enc
      • storing secure env variables for decryption
      • Make sure to add id_rsa.enc to the git repository.
      • Make sure not to add ~/.ssh/id_rsa to the git repository.
      • Commit all changes to your .travis.yml.
      • 第一行:运行命令,加密~/.ssh/id_rsa文件

      • 第二行:检测Travis绑定的GitHub源代码仓库,若正确,输入yes

      • 第三行:为GitHub源代码仓库加密本地系统的私钥文件

      • 第四行:在本地工程根目录内生成id_rsa.enc文件(已加密),.travis.yml内自动添加(清空所有备注)以下配置信息

        • before_install:
        • - openssl aes-256-cbc -K $encrypted_xxx_key -iv $encrypted_xxx_iv
        • -in id_rsa.enc -out ~\/.ssh/id_rsa -d

        实际使用时,要将\去掉,否则会编译失败。

      • 第五行:存储用于解密的安全环境变量

      • 第六行:将id_rsa.enc文件推送到GitHub源代码仓库

      • 第七行:不能将本地系统的私钥文件推送到GitHub源代码仓库

      • 第八行:.travis.yml的修改推送到GitHub源代码仓库

      .travis.yml的最终结果:

      • language: python # Travis的语言环境为Python
      • python:
      • - "3.7" # python版本指定为3.7
      • branches: # 设置分支白名单
      • only:
      • - master # 只有master分支的提交才会触发构建
      • addons:
      • ssh_known_hosts:
      • - gitee.com
      • env: # 设置环境变量
      • global:
      • # - GH_REF: github.com/koman/koman.github.io.git # GitHub发布仓库的Git地址(使用HTTPS协议)
      • - GE_REF: gitee.com:koman/koman.git # Gitee发布仓库的Git地址(使用SSH协议)
      • before_install: # 加密密码
      • - openssl aes-256-cbc -K $encrypted_abf3a382006f_key -iv $encrypted_abf3a382006f_iv -in id_rsa.enc -out ~/.ssh/id_rsa -d
      • - eval "$(ssh-agent -s)" # 开启ssh-agent,即允许使用ssh命令
      • - chmod 600 ~/.ssh/id_rsa # 给予id_rsa文件权限,避免警告
      • - ssh-add ~/.ssh/id_rsa # 将私钥添加到ssh
      • install: # 安装依赖项
      • - wget https://github.com/gohugoio/hugo/releases/download/v0.62.2/hugo_0.62.2_Linux-64bit.deb # 手动下载Hugo指定版本
      • - sudo dpkg -i hugo*.deb # 安装Hugo版本
      • script:
      • - hugo # 运行hugo命令,生成发布内容(public目录)
      • after_script: # 博客发布内容推送到发布仓库
      • - cd ./public
      • - git init
      • - git config user.name "koman"
      • - git config user.email "komantao@hotmail.com"
      • - git add .
      • - git commit -m "Update Blog By TravisCI With Build $DATE"
      • # - git push --force --quiet "https://${Github_TOKEN}@${GH_REF}" master:master
      • - git push --force --quiet "git@${GE_REF}" master:master
      • # 博客发布内容推送到GitHub的源代码仓库的另一个分支(需要时,去掉注释,即#号)
      • # deploy:
      • # provider: pages # 部署到GitHub Pages网站
      • # skip-cleanup: true # 必须为true,否则Travis会删除在构建期间创建的所有文件(即删除了计划上传的文件)
      • # local-dir: public # 要推送到GitHub Pages的目录,可以指定为当前目录的绝对路径或相对路径
      • # on:
      • # branch: master # 博客源代码所在分支
      • # target-branch: xxx # 将local-dir强制推送到哪个分支(自定义,名称不能与源代码分支名相同),默认为gh-pages
      • # github-token: $GITHUB_TOKEN # $GITHUB_TOKEN是一个变量:名称是Travis定义名称,值是GitHub的personal access token的值
      • # fqdn: xxx # 使用自定义域名(即不使用GitHub Pages网站)
      • # verbose: true # true,表示显示Travis的log
      • # keep-history: true # true,表示保持target-branch分支的提交记录
      • 使用了Ruby for Windows,因为Windows不支持openssl验证,导致Travis对密钥文件解密时触发错误,建议改用Ruby for Linux
    2. 加密密码,使用HTTPS协议push

      如果密码中有特殊符号,需要转义:例如@需要转成%40。

      • $ travis encrypt gitee_password=xxx --add

      .travis.yml文件的global变量增加一个secure字段

      • env:
      • global:
      • - secure: xxxxxx # 加密后的密码

      .travis.yml的最终结果:

      • language: python
      • python:
      • - '3.7'
      • branches:
      • only:
      • - master
      • env:
      • global:
      • - GE_REF: gitee.com/xxx/xxx.git
      • - secure: xxxxxx
      • install:
      • - wget https://github.com/gohugoio/hugo/releases/download/v0.62.2/hugo_0.62.2_Linux-64bit.deb
      • - sudo dpkg -i hugo*.deb
      • script:
      • - hugo
      • after_script:
      • - cd ./public
      • - git init
      • - git config user.name "xxx"
      • - git config user.email "xxx@xxx.com"
      • - git add .
      • - git commit -m "Update Blog By TravisCI With Build $DATE"
      • - git push --force --quiet "https://xxx:${gitee_password}@${GE_REF}" master:master
      • Ruby for Windows使用加密密码方式成功

4、Netlify

Netlify是国外一家提供静态网络托管服务的综合平台,专注于静态网站托管的web服务,完美且免费支持ssl、域名绑定、http/2和TLS,官网宣传其是一个工作流(workflow),包含构建一个网站所需的一切。

Netlify的功能:

  • 托管静态资源

    与GitHub Pages一样,但比GitHub Pages强多了,而且速度也快。两者的对比在netlify官网有介绍。

  • 将静态网站部署到CDN,加速国内访问

    GitHub Pages无法进行CDN加速。Netlify能够使用自带CDN加速服务。

  • 持续部署(Continuous Deployment)

    当博客源码提交推送到托管平台后,Netlify就会自动运行build command(自动克隆博客源码仓库,自动判断博客框架,自动运行build命令生成博客发布代码),自动部署到绑定域名。

    Netlify更关注于前端(网站或APP)的持续集成与持续部署,这是它与其他持续集成工具最大的区别。而且,Netlify的使用非常简单。

  • 可以添加自定义域名(个人购买的域名)

  • 可以启用免费的TLS证书,启用HTTPS

  • 自带CI、支持重定向、插入代码、打包和压缩JS和CSS、压缩图片、处理图片

    重定向(也称URL转发)。GitHub Pages对redirects、重定向(也称URL转发)支持并不友好,如果放弃GitHub Pages提供的username.github.io子域名时很麻烦。对比之下,从username.netlify.com重定向(重定向编码是301或302)至新发布网站时很简单。重定向后,搜索引擎可以清楚识别你的页面已被转移,从而对你的新页面进行重新排名。所以即使哪天Netlify车毁人亡,只要设定好了重定向,你的网站也不会受到任何影响。

4.1 部署流程

  1. 登录(注册)Netlify,关联GitHub帐户

    Netlify提供邮箱注册和包括GitHub在内的第三方验证登陆(注册)。

    image-20200113165140198

    1. 选择第三方(GitHub)验证登陆(注册)

    2. GitHub授权验证登陆Netlify

      image-20200113165555863

    3. 关联GitHub账户

      登录后,页面自动(或点击导航栏上方的Netlify图标)跳转到“New site from Git”,点击“New site from Git”:

      image-20200113170641881

      页面跳转到“Create a new site”,点击GitHub:

      image-20200113170934010

      Netlify首次关联GitHub仓库时,弹出窗口:

      image-20200113171237033

      点击“Authorize Netlify by Netlify”同意授权后,Netlify就有权访问GitHub仓库内容。

  2. 选择仓库

    授权完毕后,页面跳转到“Install Netlify”,选择GitHub的源代码仓库(可为私有仓库):

    image-20200113171953598

    • 备注:可在GitHub中修改Netlify的配置:帐户Settings — Applications

    点击Install后,等待一段时间,页面跳转回“Create a new site”,显示关联后的仓库:

    image-20200113173158915

  3. 构建选项和部署

    点击上图中的已关联仓库,进入第3步骤:

    image-20200113173949722

    • Owner:Netlify自动识别,已绑定了托管平台的仓库

    • Branch to deploy:被部署分支,存储源代码的分支

    • Build command:构建命令

      Netlify会自动判断博客框架,自动显示命令,可自定义参数。

    • Publish directory:发布目录,默认为public

    • show advanced:提示将netlify.toml添加到存储库中,可获得更大的灵活性

      在本地项目根目录内新建netlify.toml文件,保存后上传到GitHub的源代码仓库:

      • [build]
      • publish = "public"
      • command = "hugo"
      • [context.production.environment]
      • HUGO_VERSION = "0.62.2"
      • HUGO_ENV = "production"
      • HUGO_ENABLEGITINFO = "true"
      • [context.split1]
      • command = "hugo --enableGitInfo"
      • [context.split1.environment]
      • HUGO_VERSION = "0.62.2"
      • HUGO_ENV = "production"
      • [context.deploy-preview]
      • command = "hugo -b $DEPLOY_PRIME_URL"
      • [context.deploy-preview.environment]
      • HUGO_VERSION = "0.62.2"
      • [context.branch-deploy]
      • command = "hugo -b $DEPLOY_PRIME_URL"
      • [context.branch-deploy.environment]
      • HUGO_VERSION = "0.62.2"
      • [context.next.environment]
      • HUGO_ENABLEGITINFO = "true"

      Netlify的构建环境使用Unix。

  4. 构建并发布网站

    前面3个步骤完成后,点击上图中的“Deploy site”按钮(Netlify自动构建并发布博客内容)后,开始构建并发布网站:

    image-20200113175351176

    • 点击上方导航栏中的“Deploys”,可实时显示部署过程(log日志):
      • 仅用30秒,Netlify就完成了整个CD过程:Finished processing build request in 30.640996398s

    网站发布成功后,网站地址:“https://” + 随机生成的子域名 + “.netlify.com”。

    image-20200113180150738

  5. 美化Netlify子域

    默认情况下,基于Netlify子域访问站点。若不喜欢Netlify随机子域且没有购买自定义域名,可以将Netlify子域美化(自定义名称):

    • 方法一:点击上图中的“Domain Settings”
    • 方法二:点击上方导航栏中的“Settings” — “General” — “Site details” — “Change site name”
    • 方法三:“Settings” — “Domain management” — “Domains” — “Custom domains”

    image-20200113184702770

  6. 自定义域名

    点击上上图中的“Set up a custom domain”,进入添加域名页面:

    image-20200117124617111

    输入已购买的域名(不包含www),点击“Verify”后设置DNS(以GitHub Pages示例):

    image-20200117125825508

    • Check DNS configuration:因为尚未将域名解析到Netlify服务器。此时,需要到域名提供商绑定(购买)的域名下添加一条CNAME解析,解析的主机记录对应Netlify的子域名值(xxx.netlify.com

    要求必须拥有域名所有权才能完成所有步骤,所以自定义域名不能使用Pages网站。

    image-20200117130503668

    由于没有个人域名,此步骤暂停。

  7. 网站(Netlify子域)设置

    路径:选择网站(Netlify子域)— 导航栏点击“Settings” — Build & deploy — 编辑设置。

    设置内容有:持续部署命令、webhooks、构建映像、环境变量、注入代码、资产优化(压缩CSS/JS/图片文件)、预渲染等。

4.2 Netlify CMS

内容管理系统(content management system,简称CMS)是指在一个合作模式下,用于管理工作流程的一套制度。该系统可应用于手工操作中,也可以应用到电脑或网络。作为一种中央储存器(central repository),内容管理系统可将相关内容集中储存并具有群组管理、版本控制等功能。版本控制是内容管理系统的一个主要优势。

Netlify CMS是一款团队的编辑工具,但可以作为个人博客的在线编辑工具,可以随时随地修改、编辑博客内容,而不用考虑多设备同步的问题。

4.3 页面重定向

Netlify提供了自定义页面重定向的功能。如果你的域名或者文章结构发生了变化,可以借助重定向功能,将原来的文章URL重定向到现在的地址。

新建一个netlify.toml文件,存放在博客的根目录下,在里面添加以下内容:

  • [[redirects]]
  • from = "https://原始域名/*"
  • to = "https://自定义域名/:splat"
  • force = true

4.4 Netlify的坑

  1. Netlify通过API ID绑定GitHub仓库

    若删除了GitHub的源代码仓库,即使之后重建(名称一样),Netlify也自动部署失败。因为绑定仓库的API ID已改变,需要重新绑定。

  2. 对TOC的分层理解

    config.toml内设置startLevel = 2的前提下:

    • Netlify的TOC从H1标题(第一层)开始构建<ul>标签
    • Hugo可以从H2标题(第二层)开始构建<ul>标签

    解决方法:在config.toml内设置startLevel = 1

  3. 对嵌套列表的理解

    无序列表和有序列表混用时,Hugo正常显示,Netlify有时会格式错乱。添加了netlify.toml文件后,格式错乱问题自动解决。

5、webhook

在web上,越来越多的操作被描述为事件。webhook(网络钩子)是一种web回调或者http的push API,是向APP或者其他应用提供实时信息的一种方式。Webhook在数据产生时立即发送数据,也就是你能实时收到数据。这一种不同于典型的API,需要用了实时性需要足够快的轮询。这无论是对生产还是对消费者都是高效的,唯一的缺点是初始建立困难。webhook是一种实现事件响应的方式,用于在项目发生事件时通知外部服务器。

以Gitee示例演示webhook的用法。

原理:

webhook流程图

  1. 本地执行git push命令,push代码到Gitee仓库
  2. Gitee接收到push请求后,调用自己服务器上的一个接口
  3. 接口是一个脚本文件,可使用php、Python等脚本语言编写,实现命令的自动执行:例如git pull和重启服务等命令

八、CDN

GitHub Pages和Netlify的服务器都部署在海外,在国内访问本博客的速度会比较慢 (Ping 下来100到200多毫秒)。解决这一问题的最优解就是使用CDN。

CDN(Content delivery network或Content distribution network,内容分发网络)是指一种通过互联网互相连接的计算机网络系统,利用最靠近每位用户的服务器,更快、更可靠地将音乐、图片、影片、应用程序及其他文件发送给用户,来提供高性能、可扩展性及低成本的网络内容传递给用户。

简单来说,CDN就是部署在世界各地的缓存服务器,它们会提前缓存网站上的资源,然后当用户想要访问相关资源时,直接从CDN服务器上取就可以了。这样不仅可以增加访问速度、减少访问延迟,还可以减缓网站服务器上的压力。

要使用CDN,需要在域名提供商更改DNS服务器,变为它提供的域名服务器地址。CDN服务提供商有很多,国内的有七牛云、阿里云、腾讯云等,国内的CDN都要求域名在公安局备案。国外的不需要备案。

Cloudflare是全球最大的DNS服务提供商之一 (号称全球最快的DNS1.1.1.1就是它搞的)。除此之外,还提供CDN、SSL证书、DDos保护等服务,Cloudflare还与百度有合作,在国内部署有大量的节点,还能顺便解决百度爬虫无法抓取GitHub Pages的问题。

Cloudflare注册一个帐号,注册好后点击“Add site”添加你的网站:

image-20200114010426839

没有个人网站,此步骤暂停。

九、评论系统

若使用国内的评论插件,前提是网站需要在公安局备案,因此转向使用国外的评论插件。

1、Gitalk

官方的GitHub仓库: https://github.com/gitalk/gitalk/

官方网站:https://gitalk.github.io/

Gitalk是一个基于GitHub Issue和Preact开发的评论插件,支持多种语言 (包括en、zh-CN、zh-TW、es-ES、fr)并自动判断当前语言。最重要的是Gitalk使用的是GitHub Issue的api,不依赖任何第三方平台。也就是说,只要Github不倒闭,你的评论系统就不会被关闭。

原理:Hugo是将Markdown文档按照主题 (包括HTML模板、CSS、JavaScript等) 编译成静态网页。所以只需要将Gitalk作为一个<div>插入到HTML模板中,然后在config.toml中添加相关配置,就可以实现“评论区”了。

步骤为:

  1. 新建一个评论仓库

    新建一个仓库(或博客发布仓库)作为存放评论的仓库(The repo to store comments),点击菜单栏中的“Settings”,勾选“Issues”,Gitalk会将评论放在这个仓库的issues里面。

  2. 注册Github Application

    在GitHub注册一个Oauth Application,让Gitalk有权限操作GitHub上的仓库。

    • 方法一:帐户“Settings” — “Developer settings” — “OAuth Apps”— “New OAuth App”
    • 方法二:点击链接Github Oauth Application

    OAuth application的新建页面:

    image-20200120112205356

    • 点击“Register application”注册后,记下Client IDClient Secret备用
    • 注册后,可在“Developer settings” — “OAuth Apps"中查看或修改
  3. 添加模板gitalk.html

    在主题的layouts/partials目录中新建gitalk.html文件:

    • {{ if .Site.Params.enableGitalk }}
    • <div id="gitalk-container"></div>
    • <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
    • <script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
    • <script>
    • const gitalk = new Gitalk({
    • clientID: '{{ .Site.Params.Gitalk.clientID }}',
    • clientSecret: '{{ .Site.Params.Gitalk.clientSecret }}',
    • repo: '{{ .Site.Params.Gitalk.repo }}',
    • owner: '{{ .Site.Params.Gitalk.owner }}',
    • admin: ['{{ .Site.Params.Gitalk.owner }}'],
    • id: location.pathname, // Ensure uniqueness and length less than 50
    • distractionFreeMode: false // Facebook-like distraction free mode
    • });
    • (function() {
    • if (["localhost", "127.0.0.1"].indexOf(window.location.hostname) != -1) {
    • document.getElementById('gitalk-container').innerHTML = 'Gitalk comments not available by default when the website is previewed locally.';
    • return;
    • }
    • gitalk.render('gitalk-container');
    • })();
    • </script>
    • {{ end }}
    • 建议直接将gitalk的资源文件下载放到项目目录中(本地引用gitalk.min.js插件)
    • 使用国内的CDN(https://www.bootcdn.cn/搜索gitalk)在线引用

    主题(themes/hugo-theme-docdock/layouts/partials/custom-content-footer.html)调用gitalk.html文件,放置位置在版权信息前面:

    • {{ partial "gitalk.html" . }}
  4. 配置config.toml

    config.toml中添加以下配置(参数名称对应gitalk.html文件中的命名):

    • [params]
    • enableGitalk = true # true时,开启Gitalk评论插件
    • [params.gitalk]
    • clientID = "xxx" # GitHub应用程序(Gitalk)生成的client ID
    • clientSecret = "xxx" # GitHub应用程序(Gitalk)生成的client secret
    • repo = "discuss" # 存储评论(comments)的仓库名
    • owner = "xxx" # GitHub仓库的所有者(owner)的GitHub ID
    • admin= "xxx" # GitHub仓库的所有者和合作者(collaborators),指对仓库具有写访问权限的用户
    • id= "location.pathname" # 页面的唯一ID,标记评论是哪个页面,并且长度小于50
    • labels= "gitalk" # Github的issue标签
    • perPage= 15 # 分页大小(Pagination size),最大为100
    • pagerDirection= "last" # 评论排序方向,可用值为'last'和'first'
    • createIssueManually= false # true时, 无干扰模式(在评论仓库的issue内不显示管理员登录信息)
    • distractionFreeMode= false # true时,启用热键(cmd|ctrl + enter)提交评论
    • 配置请参考:https://github.com/gitalk/gitalk
  5. 初始化评论区

    设置好后,将博客内容推送到发布网站,首次启用Gitalk需要初始化(运行hugo server时,gitalk.html文件设置不启用Gitalk)。未初始化时,弹出警告提示如下:

    image-20200113225215637

    使用注册Github Application时的账号登陆并授权:

    image-20200113225528620

    授权后进入每一篇博客刷新页面,才能激活每一篇博客的评论区。

十、SEO

SEO(Search Engine Optimization,搜索引擎优化),利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名。目的是让其在行业内占据领先地位,获得品牌收益。

检查网站是否被收录:Google/百度搜索框输入site:yoursite.github.io

验证网站:Google搜索引擎百度搜索引擎

验证方法:

  • 文件验证(简单方便,推荐使用)
  • html标签验证
  • CNAME验证

网站上线后,做SEO时需要检查如下内容:

  • 集成Google Analytics或百度统计

  • 为页面增加header信息,如title和description

  • sitemap.xml

    将网站生成工具自动生成的站点地图的URL提交给Google Webmaster Tools。

  • robots.txt

    阻止搜索引擎爬取网站上的敏感网页。

  • 结构化数据:可以帮助爬虫理解页面内容,参考HTML5的结构化数据

1、网站内容优化

  1. 描述(description)

    config.toml中设置网站描述信息:

    • [params]
    • description = "xxxxxx"

    在每篇文章的扉页中设置文章描述信息:

    • +++
    • description = "Where you should come to find my homepage updates and stuff"
    • +++

    themes/hugo-theme-docdock/layouts/partials/original/head.htmlthemes/hugo-theme-docdock/layouts/partials/original/custom-head.html文件(简称head.html)中添加<meta>标签:

    • <meta name="description" content="{{ with .Description }}{{ . }}{{ else }}{{ with .Site.Params.description }}{{ . }}{{ end }}{{ end }}">
  2. 文章关键词(keywords)

    在每篇文章的扉页中设置keywords:

    • +++
    • keywords = [mysite,mysite keyword,Another useful keyword]
    • +++

    然后,在<head>标签(head.html)内添加<meta>标签:

    • <meta content="{{ delimit .Keywords ", " }}" name="keywords">
  3. 文章标题(title)

    每篇文章都应有一个标题,方便搜索引擎收录。Hugo生成的文章会在<head>标签内自动添加<title>标签。若无,在文章模板的<head>标签内添加<title>标签。

    • <title>{{ $isHomePage := eq .Title .Site.Title }}{{ .Title }}{{ if eq $isHomePage false }} - {{ .Site.Title }}{{ end }}</title>

    也可以在<meta>标签中添加标题标签。

    • <meta content="{{ $isHomePage := eq .Title .Site.Title }}{{ .Title }}{{ if eq $isHomePage false }} - {{ .Site.Title }}{{ end }}" property="og:title">

2、Google搜索优化

  1. 进入Google Search Console

    打开Google网站站长,点击“SEARCH CONSOLE ”进入:

    image-20200117164644387

    • 网域:需要验证DNS,因此只适用于个人域名
    • 网址前缀:Pages网站只能选择此方法,输入完整网址后,点击“继续”按钮
  2. 验证所有权

    进入验证页面:

    image-20200117170542353

    要求下载一个html文件(google××××.html),将这个html文件保存到hugo站点根目录内的static子目录,提交推送到被验证网站后,回到验证页面点击“验证”。

  3. 资源

    验证成功后,点击“前往资源页面”:

    image-20200117170730185

    点”索引”下的”站点地图”,

    image-20200117171415848

    在”添加新的站点地图”处输入被验证网站的sitemap(自动生成,存放在网站根路径):

    image-20200117172801027

    等待一天左右就可以搜到了!

3、baidu搜索优化

打开百度搜索资源平台的链接提交,输入网址:

image-20200122001242571

提交后,百度不保证一定能够收录您提交的链接。

点击“用户中心” — “站点管理” — “添加网站”时,或使用站长工具需要实名认证。

和Google不一样,百度不容许以子目录的方式提交子站点,https://xxx.github.io/xxx/`的形式就不能直接提交了,只能在提交sitemap文件时,提交多个sitemap文件。这样也能勉强让百度收录。

十一、脑图

Hugo除了能够制作个人博客网站外,还能制作脑图(mindmap,又称思维导图)和HTML格式的幻灯片(slide)。

1、Hugo制作脑图

参阅:Hugo中使用思维导图。此方法尚未实现。

想要在blog中插入脑图,之前一直都在使用插入图片的方法,这样非常不优雅。

基于百度的kityminder修改为适用于Hugo:

  1. 这里下载插件

    • kity.min.js:svg(可缩放矢量图)渲染库,放入hugo目录的**static/js/**中
    • kityminder.core.min.js:脑图渲染库,放入hugo目录的**static/js/**中
    • mindmap.jsmindmap.min.js:将li标签(Markdown的列表)转换成脑图需要的json文件,放入hugo目录的**static/js/**中
    • mindmap.css:脑图渲染库,放入hugo目录的**static/css/**中
  2. 在线引用jquery.min.js插件

    • <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

    通常情况下,主题已具备,不需要另外准备。

  3. 这里下载kityminder.css,改名为kityminder.core.css,放入hugo目录的**static/css/**中

  4. 引用文件

    在模板的head标签(themes/hugo-theme-docdock/layouts/partials/original/head.html)内引用文件:

    • <link href="{{.Site.BaseURL}}css/kityminder.core.css" rel="stylesheet">
    • <link href="{{.Site.BaseURL}}css/mindmap.css" rel="stylesheet">
    • <script src="{{.Site.BaseURL}}js/kity.min.js"></script>
    • <script src="{{.Site.BaseURL}}js/kityminder.core.min.js"></script>
    • <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script></script>
    • <script src="{{.Site.BaseURL}}js/mindmap.js"></script>
    • jquery.slim.min.js导致TOC失败,删除
  5. 使用shortcodes(简码)将Markdown渲染为html

    在hugo目录layouts/shortcodes下新建一个 html(例如为mind.html):

    • <div id="{{ .Get 0 }}" class="mindmap">
    • {{- .Inner -}}
    • </div>

    这个shortcodes非常简单,就是将其中的内容渲染出来套个div标签,加上mindmap的类名。

  6. 然后在Markdwon中添加文本

    • { {< mind mindid >}}
    • - 根目录
    • - 一级目录1
    • - 二级目录1
    • - 二级目录2
    • - 一级目录2
    • { {< /mind >}}

    凡事都不会一帆风顺。Hugo渲染后无显示结果

    • 首先,在模板的head标签内引用文件后,导致页面的TOC失效,删除引用jquery.slim.min.js,TOC恢复正常
    • 然后,查看控制台(Console)发现是mindmap.js触发错误:Uncaught TypeError: Cannot read property ‘childNodes’ of undefined
  • 问题尚未解决(放弃)

2、Hugo引用脑图

通过Hugo制作的脑图,实现的功能和样式单一。现改变思路:Hugo引用脑图的HTML文件。此方法的脑图的功能和样式由制作工具决定,缺点是转换的HTML文件容量比较大。

  • 首先,通过专用工具(例如mindmanager)制作脑图,脑图导出为HTML文件

    下载mindmanager版本,搜索注册码(目前可用:MP20-345-DP56-7778-919A)破解。制作脑图后,“另存为”时选择保存类型为HTML5交互式导图(*.html)。

  • 然后,Hugo引用脑图导出的HTML文件

    假设脑图的HTML文件为Git.html,必须存放在static目录内。避免被Hugo渲染。否则,Hugo渲染脑图文件时会触发错误(命令中存在“-”字符):

    Rebuild failed: “E:\xxx\xxx.html:16:1”: template: __E:\xxx\xxx.htmlHTML:16: unexpected bad character U+002D ‘-’ in command

    16 < script id="mmap-config” type="text/plain">{{mmap-config}}< /script >

    • 方法一:使用button简码跳转到指定页面显示脑图

      优点是布局简洁且不影响当前页面的加载速度(需要时,才点击按钮,在本页面显示脑图的HTML文件内容。缺点是覆盖了本页面(来回切换页面)。

      button简码默认在本页跳转到指定页面(onclick="location.href='{{.}}'"),修改后(onclick="window.open('{{.}}')"),可在新页跳转到指定页面。

      docDock主题的button简码(button.html)的源代码为:

      • <!-- Boutton -->
      • {{ with .Get "align" }}<center>{{end}}
      • <button class="btn {{with .Get "theme"}}btn-{{.}}{{else}}btn-primary{{end}}" type="button" {{ with .Get "href" }} onclick="location.href='{{.}}'"{{end}} >{{.Inner}}</button>
      • {{ with .Get "align" }}</center>{{end}}
      • <!-- Boutton -->
      • href="url”:url可为任意文件类型。若为本地文件时,url路径相对于static目录。

      在Markdown文件中使用button简码:

      • { {< button href="/images/Git.html" >}} Git的思维导图 { {< /button >}}
    • 方法二:使用<iframe>框架跳转到子页面显示脑图

      优点是在当前页面显示另一个HTML页面(又称外部页面、子页面)的内容且能自定义CSS;缺点是脑图文件过大,严重影响当前页面的加载速度。

      1. 定义一个<iframe>框架

        在当前页面嵌套子页面:

        • <iframe id="xxx" name="xxx" frameborder="0" style="display:block;width:100%; height:545px;" src="url"></iframe>
        • id或name=“xxx”:区分不同的子页面

        • frameborder="0|1”:0表示无边框;1表示有边框

        • style="CSS”:设置子页面的CSS

          width为子页面的宽,height为子页面的高;可以使用百分比,会自适应父容器的百分比,也可以使用固定的行高列宽:100px,60px。

        • src="url”:设置子页面的关联url(链接地址),url可为任意文件类型

        • scrolling="auto|yes|no”:是否显示子页面滚动条,缺省时值为auto

      2. 若只打算在Markdown文件中显示脑图

        需要在config.toml文件中开启unsafe = true,url输入脑图的相对路径(相对于当前的Markdown文件)。

      3. 若打算在Hugo(个人博客)中显示脑图

        1. 新建(<iframe>框架修改为)一个简码文件(存入layouts/shortcodes目录,假设为mind.html):

          • <iframe id="{{ .Get 0 }}" name="{{ .Get 0 }}" frameborder="0" style="display:block;width:100%; height:545px;" src="{{ .Get 1 }}">
          • </iframe>
          • {{ .Get 0 }}:0表示使用第一个传入参数;1表示使用第二个传入参数
        2. Markdown文件使用简码:

          • { {< mind mindid "/images/Git.html" >}}
          • 第一个参数是简码名称、第二个参数传递给id和name、第三个参数传递给src(脑图的HTML文件,存入static目录,路径相对于static目录)

十二、幻灯片

幻灯片,是使用全屏来显示Markdown文件内容的页面。

Markdown文件内容可以呈现为全屏的manifest.js演示文稿。manifest.js使您可以使用HTML创建漂亮的交互式幻灯片。参阅:PRESENT A SLIDE

  1. 在Markdown文件的扉页中设置type="slide"[revealOptions]

    • +++
    • title = "Test slide" # Markdown文件的标题
    • type="slide" # Markdown文件的类型:slide(幻灯片)
    • theme = "league" # revel.js框架(幻灯片)的主题
    • [revealOptions]
    • transition= 'concave' # 幻灯片过渡类型值:none|fade|slide|convex|concave|zoom
    • controls= true # 显示幻灯片的控制箭头
    • progress= true # 显示幻灯片的演示进度条
    • history= true # 将每个幻灯片的更改记入浏览器历史记录
    • center= true # 滑块垂直对中
    • +++
    • 参数参阅:https://github.com/hakimel/reveal.js/#configuration
  2. 幻灯片定界符

    在Markdown文件中为幻灯片演示文稿创建内容时,使用定界符区分每一张幻灯片:

    • 水平幻灯片的定界符:3个减号---

    • 垂直幻灯片的定界符:3个下划线___

      通常,垂直幻灯片用于在顶层水平幻灯片下方显示信息。

  3. 创建幻灯片内容

    使用#标记标题的层级

    • # In the morning

Getting up

  • Turn off alarm
  • Get out of bed

Breakfast

  • Eat eggs
  • Drink coffee

In the evening


Dinner

  • Eat spaghetti
  • Drink wine

Going to sleep

  • Get in bed
  • Count sheep
  • 4. 使用HTML语法实现各种功能
  • reveal.js控制幻灯片的行为和样式,Markdown控制幻灯片的内容,HTML语法控制幻灯片的多媒体功能。Hugo的设置(例如:**config.toml**内的设置、简码等)在幻灯片中无效,可直接使用HTML语法扩展幻灯片的多样化功能。
  • ## 参考资料
  • > 官网:
  • >
  • > - [Hugo官网](https://gohugo.io/)
  • > - [Hugo官网中文镜像](https://s0gohugo0io.icopy.site/ )
  • > - [Hugo官方教程(英文)Hugo Docs](https://gohugo.io/documentation/)
  • > - [HUGO LEARN THEME](https://learn.netlify.com/en/)
  • > - [Travis CI官方文档](https://docs.travis-ci.com/)
  • > - [Netlify官方文档](https://docs.netlify.com/)
  • >
  • > 个人博客:
  • >
  • > - [Tutorials for the Hugo static site generator](https://kodify.net/hugo-static-site-tutorials/)
  • > - [Blog养成记](https://orianna-zzo.github.io/series/blog养成记/)
  • > - [本站引用图片的“顺滑”流程](https://rayhy.com/blog/20190301-本站引用图片的顺滑流程/)
  • > - [Hugo静态网站生成器中文教程](http://nanshu.wang/post/2015-01-31/)
  • > - [Hugo 搭建博客实践](https://creaink.github.io/post/Devtools/Hugo/Hugo-intro.html)
  • > - [使用Hugo建个网站](https://lyzhang.me/post/make_a_blog_with_hugo/)
  • > - [hugo中文帮助文档](https://hugo.aiaide.com/)
  • > - [Hugo学习笔记](https://skyao.io/learning-hugo/)
  • > - [苏洋博客](https://soulteary.com/)
  • > - [静态网站构建手册-使用Hugo构建个人博客](https://jimmysong.io/hugo-handbook/)
  • ## 操作环境
  • > - 操作系统:Win 10
  • > - Hugo工具:hugo_0.61.0_Windows-64bit

感谢您的赞赏支持:

0 comments
Anonymous
Markdown is supported

Be the first person to leave a comment!

Copyright © 2020 komantao. All Rights Reserved.