从零构建Hugo主题 - I
这是一个系列博客,记录了我从零开始构建Hugo主题https://github.com/tomowang/hugo-theme-tailwind的过程。全系列包括四篇文章,这是第一篇:
- I. 主要介绍我构建Hugo主题的背景,我对主题的功能想法,以及开发环境的搭建
- II. Hugo主题的主要目录结构,需要了解的技术,以及我创建的主题的主体框架
- III. Hugo主题的其他功能,包括黑色主题,响应式设计,多语言,代码高亮,构建管道等
- IV. 该部分描述非代码相关的内容,包括持续集成(CI),如何提交至官方主题站点,以及SEO相关的数据等
背景
我是一名开发者,在过往十多年的开发经历中,我接触到各种技术,如前端、后端、大数据、机器学习等。
当我期望将我的个人开发尝试或者生活经历对外分享的时候,我萌生了构建博客站点的想法。
在我最初的博客选型中,有不少候选项,如WordPress,Hexo,Jekyll等等,最终我选择了hugo静态页面生成的模式,
并且为我的博客站点挑选了一个还不错的域名tomo.dev。
选择hugo的原因很简单,hugo是用golang
开发的,安装和构建速度很快,开源,有着完善社区,
并且有着丰富的官方文档,同时hugo有较多开源主题。当然为自己的站点挑选主题一直是个头疼的事情,
在浏览了官方主题站点中众多的主题后,我最终选择一款名为hello friend
的主题。
hello friend
有着较为简洁的页面结构,不算复杂的代码,并且支持黑白主题切换以及响应式设计,
最终我写下了我的第一篇博客:https://tomo.dev/posts/blog-using-hugo/。
在之后的博客撰写过程中,我在hello friend
主题中加了一些功能,调整了一些页面结构,
比如在底部导航加了我的GitHub地址,调整了部分JavaScript代码并加了一些新的三方JavaScript库。
我的文章都是用中文撰写,博客上线两年后一直没什么流量。在2023下半年的时候,
我开始接触web站点推广方面的工作,如SEO等,于是我想着怎么将我的博客翻译成英文并做些SEO尝试。
但是hello friend
主题本身不支持多语言,且其代码不再维护(不过后来发现有个后继者hello friend ng
)。
同时我脱离前端开发有段时间,了解到tailwindcss
比较火,想跟上前端新趋势的步伐,
于是便萌生了自己构建主题的想法。
功能
构建主题和使用主题是完全两种模式。使用主题时,大部分时候只需要了解简单的配置,熟悉markdown
语法就可以了。
但是构建主题相当于开发一个小型的产品或者插件,我需要回答这样的一些问题:
- 主题的风格和布局是什么的?
- 有哪些功能?
- 需要什么样的技术能力?
- 如何发布、推广并让更多人使用?
我不是产品经理,也不是设计师,但是市面上有不少开源的主题我可以参考。我期望我的主题像hello friend
一样有着简洁的布局,同时尽量少地使用复杂前端技术,并且容易扩展,SEO友好。
关于技术,tailwindcss
是比较明确的,我使用过bootstrap
,vuetify
,ant design
等前端组件库,
学习一个新的CSS库应该不会太难。而关于hugo主题相关技术,目前已知的是需要golang的html/template
的一些语法知识,剩下的可以在过程中查阅官方文档。
最终我参考一些已有的主题,以及tailwindcss
的示例站点,画了简单的页面布局图,
包含logo、导航菜单、多语言切换、黑色主题切换、文章列表、术语展示块、底部社交媒体链接、底部版权声明等
基于原型图,梳理了主要的功能
- 基础功能:导航及菜单,列表页,文章页面,右侧分类列表以及分类的列表页、详情页
- Darkmode - 黑色主题切换
- 响应式设计
- 多语言
- 图片处理
- 底部导航的社交媒体链接
以及其他支撑这些功能以及开源项目的隐藏需求:
- 持续集成
- 文档,配置示例
- lighthouse评分
- 其他
- short code的尝试
- Google Analytics 配置
- 用户评论功能
- Social tag
- 代码块复制功能
然后需要给主题一个名称,浏览了下官方主题列表,最后我选择了hugo-theme-tailwind
。
事实证明好的名字会给项目带来额外的一些曝光和流量。
初始化github仓库,提交了第一个#d833043。
开发环境准备
为了构建新的Hugo主题,我们需要hugo,nodejs。工具的安装不是这系列文章的重点,可以参考一些官方文档:
- hugo - https://gohugo.io/installation/
- nodejs环境 - 我使用的是fnm及pnpm
有了hugo命令,在仓库的目录下执行如下命令:
hugo new theme hugo-theme-tailwind
该命令会在当前目录创建文件夹themes/hugo-theme-tailwind
,我们需要将其移动到我们的仓库中,同时移除主题自带的内容content
目录。
mv themes/hugo-theme-tailwind/* .
rm -rf themes/
rm -rf content
下载官方提供的示例站点内容到主题的exampleSite
目录下
git clone https://github.com/gohugoio/hugoBasicExample.git exampleSite
rm -rf exampleSite/.git
在示例站点的配置文件中添加主题配置:theme = "hugo-theme-tailwind"
,
然后运行命令
hugo server -s exampleSite --gc --themesDir=../..
该命令会启动hugo服务,可以测试最原始的主题展示情况,示例日志输出如下:
Start building sites …| EN
-------------------+-----Pages | 41Paginator pages | 0Non-page files | 0Static files | 2Processed images | 0Aliases | 9Sitemaps | 1Cleaned | 0Built in 13175 ms
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
访问http://localhost:1313/,可以见到如下图的简单页面
至此我们有了简单的可以运行的初始主题和示例站点,后面我将基于该原始主题进行扩展和改写。
相关文章:

从零构建Hugo主题 - I
这是一个系列博客,记录了我从零开始构建Hugo主题https://github.com/tomowang/hugo-theme-tailwind的过程。全系列包括四篇文章,这是第一篇: I. 主要介绍我构建Hugo主题的背景,我对主题的功能想法,以及开发环境的搭建…...

【HarmonyOS应用开发】HTTP数据请求(十四)
文章末尾含相关内容源代码 一、概述 日常生活中我们使用应用程序看新闻、发送消息等,都需要连接到互联网,从服务端获取数据。例如,新闻应用可以从新闻服务器中获取最新的热点新闻,从而给用户打造更加丰富、更加实用的体验。 那么…...

MongoDB聚合: $sortByCount
$sortByCount聚合根据指定表达式的值对输入文档进行分组,然后计算每个不同分组中的文档数。 每个输出文档包含两个字段:一个是包含不同分组值的_id字段,另一个是包含属于该分组或类别的文档数量的计数字段。 文档按计数降序排序。 语法 {…...

FY-SA-20237·8-AI‘sIQ
Translated from the Scientific American, July/August 2023 issue. AI’s IQ ChatGPT aced a test but showed that intelligence cannot be measure by IQ alone. —— By Eka Roivainen 翻译:ChatGPT在一项测试中取得了优异的成绩,但也表明智力不能…...

react将选中文本自动滑动到容器可视区域内
// 自动滚动到可视区域内useEffect(() > {const target ref;const wrapper wrapperRef?.current;if (target && wrapperRef) {const rect target.getBoundingClientRect();const wrapperRect wrapper.getBoundingClientRect();const isVisible rect.bottom &l…...

Rust语言入门小结(第1篇)
Rust是一种新兴编程语言,既有高级语言的风格,又有底层语言级别的性能;是对于实时性、安全性要求高的应用开发的理想语言。 笔者的自学记录,供参考 环境搭建与第一个Rust程序 以Linux环境为例 # 下载并安装 curl --proto https -…...

前端实现支付跳转以及回跳
// 支付地址 const baseURL http://pcapi-xiaotuxian-front-devtest.itheima.net/ const backURL http://127.0.0.1:5173/paycallback const redirectUrl encodeURIComponent(backURL) const payUrl ${baseURL}pay/aliPay?orderId${route.query.id}&redirect${redirec…...

黑豹程序员-封装组件-Vue3 setup方式子组件传值给父组件
需求 封装组件 需要使用到Vue3中如何定义父子组件,由子组件给父组件传值 核心代码 如何使用emits 组件 <template><button click"sendData">点击按钮</button> </template><script setup> import {ref, defineEmits}…...

PySpark(三)RDD持久化、共享变量、Spark内核制度,Spark Shuffle、Spark执行流程
目录 RDD持久化 RDD 的数据是过程数据 RDD 缓存 RDD CheckPoint 共享变量 广播变量 累加器 Spark 内核调度 DAG DAG 的宽窄依赖和阶段划分 内存迭代计算 Spark是怎么做内存计算的? DAG的作用?Stage阶段划分的作用? Spark为什么比MapReduce快? Spa…...

PCIE Order Set
1 Training Sequence Training Sequence是由Order Set(OS) 组成,它们主要是用于bit aligment,symbol aligment,交换物理层的参数。当data_rate 2.5GT or 5GT 它们不会被扰码(scramble),当date_rate 8GT or higher 根据特殊的规则…...

nginx upstream server主动健康检测模块ngx_http_upstream_check_module 使用和源码分析(下)
目录 7. 实现一个UDP健康检测功能7.1 功能定义7.2 定义一个新的健康检测类型7.3 增加udp特定的健康检测需要的配置指令7.3.1 ngx_http_upstream_check_srv_conf_s结构体的扩展7.3.2 check_udp_send的实现7.3.3 check_udp_expect的实现7.3.4 16进制解码代码的实现7.4 ngx_http_u…...

基于SSM的网络在线考试系统(有报告)。Javaee项目。ssm项目。
演示视频: 基于SSM的网络在线考试系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构,通过Spring …...

【Flink状态管理(二)各状态初始化入口】状态初始化流程详解与源码剖析
文章目录 1. 状态初始化总流程梳理2.创建StreamOperatorStateContext3. StateInitializationContext的接口设计。4. 状态初始化举例:UDF状态初始化 在TaskManager中启动Task线程后,会调用StreamTask.invoke()方法触发当前Task中算子的执行,在…...

python+flask人口普查数据的应用研究及实现django
作为一款人口普查数据的应用研究及实现,面向的是大多数学者,软件的界面设计简洁清晰,用户可轻松掌握使用技巧。在调查之后,获得用户以下需求: (1)用户注册登录后,可进入系统解锁更多…...

C语言:函数
C语言:函数 函数的概念库函数自定义函数实参与形参return语句数组做参数声明与定义externstatic 嵌套调用 函数的概念 在C语言中,存在一个函数的概念,有人也将其翻译为子程序。 在数学中,函数是一个完成特定功能的公式࿰…...

jmeter-问题一:关于线程组,线程数,用户数详解
文章目录 jmeter参数介绍1.线程数2.准备时长(Ramp-up)3.循环次数4.same user on each iteratio5.调度器 场景一:当你的线程组中线程数为1,循环为1场景二:当你的线程组中线程数为2,循环为1场景三:当你的线程组中线程数为1ÿ…...

golang 通过 cgo 调用 C++ 库
思路 将 C 库包装成 C 库 -> golang 通过 cgo 调用 C 库 C 相关文件 目录列表 include/ some.h C 库头文件some_wrapper.h < 用于将 C 库包装成 C 库的头文件 lib/ libsome.a C 库 src/ some_wrapper.cpp < 用于将 C 库包装成 C 库的源码文件 源码示例 some.h…...

使用 IDEA 开发一个简单易用的 SDK
目录 一、什么是 SDK 二、为什么要开发 SDK 三、开发 SDK 的详细步骤 四、导入 SDK 进行测试 附:ConfigurationProperties 注解的介绍及使用 一、什么是 SDK 1. 定义:软件开发工具包 Software Development Kit 2. 用于开发特定软件或应用程序的工…...

CSS transition(过渡效果)详解
CSS过渡效果(Transition)是一种在CSS3中引入的动画效果,它允许开发者在元素状态变化时(如鼠标悬停、类更改等)平滑地改变CSS属性值,从而创建出平滑的动画效果。过渡效果可以应用于多种CSS属性,如…...

Android13多媒体框架概览
Android13多媒体框架概览 Android 多媒体框架 Android 多媒体框架旨在为 Java 服务提供可靠的接口。它是一个系统,包括多媒体应用程序、框架、OpenCore 引擎、音频/视频/输入的硬件设备,输出设备以及一些核心动态库,比如 libmedia、libmedi…...

一文读懂:MybatisPlus从入门到进阶
快速入门 简介 在项目开发中,Mybatis已经为我们简化了代码编写。 但是我们仍需要编写很多单表CURD语句,MybatisPlus可以进一步简化Mybatis。 MybatisPlus官方文档:https://www.baomidou.com/,感谢苞米豆和黑马程序员。 Mybat…...

C语言--------指针(1)
0.指针&指针变量 32位平台,指针变量是4个字节(32bit/84)--------x86 64位平台,指针变量是8个字节(64bit/88)--------x64 编号指针地址;我们平常讲的p是指针就是说p是一个指针变量; ************只要…...

Vite 下一代的前端工具链,前端开发与构建工具
一、Vite 简介 官方中文网站:Vite | 下一代的前端工具链 官方定义: Vite,下一代的前端工具链,为开发提供极速响应。 Vue3.4版本,Vue新版本使用Vite构建、开发、调试、编译。 Vite的优势 极速的服务启动 使用原生…...

【SpringBoot】FreeMarker视图渲染
目录 一、FreeMarker 简介 1.1 什么是FreeMarker? 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…...

巴尔加瓦算法图解:算法运用。
树 如果能将用户名插入到数组的正确位置就好了,这样就无需在插入后再排序。为此,有人设计了一种名为二叉查找树(binary search tree)的数据结构。 每个node的children 都不大于两个。对于其中的每个节点,左子节点的值都比它小,…...

Docker的镜像和容器的区别
1 Docker镜像 假设Linux内核是第0层,那么无论怎么运行Docker,它都是运行于内核层之上的。这个Docker镜像,是一个只读的镜像,位于第1层,它不能被修改或不能保存状态。 一个Docker镜像可以构建于另一个Docker镜像之上&…...

忘记 RAG:拥抱Agent设计,让 ChatGPT 更智能更贴近实际
RAG(检索增强生成)设计模式通常用于开发特定数据领域的基于实际情况的ChatGPT。 然而,重点主要是改进检索工具的效率,如嵌入式搜索、混合搜索和微调嵌入,而不是智能搜索。 这篇文章介绍了一种新的方法,灵感…...

利用路由懒加载和CDN分发策略,对Vue项目进行性能优化
目录 一、Vue项目 二、路由懒加载 三、CDN分发策略 四、如何对Vue项目进行性能优化 一、Vue项目 Vue是一种用于构建用户界面的JavaScript框架,它是一种渐进式框架,可以用于构建单页应用(SPA)和多页应用。Vue具有简单易学、灵…...

【Scala】1. 变量和数据类型
1. 变量和数据类型 1.1 for begining —— hello world 新建hello.scala文件,注意object名字与文件名一致。 object hello { def main(args:Array[String]): Unit { println("hello world!") } }运行后打印结果如下: hello world!Pr…...

何时以及如何选择制动电阻
制动电阻的选择是优化变频器应用的关键因素 制动电阻器在变频器中是如何工作的? 制动电阻器在 VFD 应用中的工作原理是将电机减速到驱动器设定的精确速度。它们对于电机的快速减速特别有用。制动电阻还可以将任何多余的能量馈入 VFD,以提升直流母线上的…...