前言#
首先,我愧疚地承认我之前写的装修博客十分偷懒地省略了很多步骤,所以那篇博客的实现细节并没有写得很详细,编程知识有限的朋友们看那篇装修笔记可能会有点吃力……发现有好多朋友在参考那篇博客时都遇到了比较类似的基础问题,所以想再写一篇很基础向的博客来介绍搭建博客前需要了解的一些知识。
重中之重:信息检索能力#
在正式开始介绍搭建博客所需要的编程知识之前,我认为有一项更重要的事情需要提一下,which is 获取信息的能力。虽然看起来好像很废话,但是也有挺多想要分享的。
这一部分的内容与搭建博客不太直接相关呢,不过我也不知道放哪比较好,就还是在这里说吧
一定要读官方文档!#
只要某个东西有足够多的人使用,那么它一定会有个详细的官方文档——比如留学申请一定是先去看学校官网上的申请要求而不是先搜小红书;签证要求先去看移民局官网而不是先问AI等等,获取任何信息时请优先考虑去官方网站查看最新资料,一直吃网友(或AI)给的二手信息真的很容易掉坑里。当然也有一些官方文档比较不清晰,但是这种情况下也最好结合网友给的二手信息与官方文档互相对照比较好。
以此类推,搭建博客时请一定要看自己要用的主题的官方文档!以我所使用的Blowfish为例子,它的官方文档提供了很多也很全面的信息,如图:
就这么一瞥感觉头已经在痛了,那么多文档!但是只需要大概扫一遍,了解【官方文档提供哪些信息】以及【什么信息在什么位置】就可以了。
比如这个【局部模板】文章,粗看标题真是有点搞不懂是指什么东西,点进来后发现有提供评论功能和修改网站图标功能等,是我想要的功能,所以我只需要这么大概记得Blowfish提供这些功能就足够了,等我真正要用的时候再站内搜索一下就能很快捷地找到该内容!
如何选择搜索平台?#
看完官方文档后,我们就会发现有些想装修的东西在官方文档里大概率是没有提到的,比如在博客里添加NeoDB卡片,一般博客主题不会提到这么一个功能,需要大家自行摸索。我一般是直接去搜,想要什么功能搜什么,但是怎么搜也是有说头的呢,先从搜索平台讲起。
我的首选是谷歌和Bing,除此之外DuckDuckGo的搜索结果质量也挺不错的。国内所有的搜索引擎都很差……几乎就是不能用的状态,大部分内容都搜不到。AI目前是没办法直接取代搜索引擎的,感觉大家对这一点都深有体会吧,AI会自己整理总结一堆看起来有联系但其实完全在讲两个事情的文章后给出一个不能直接使用的答案🚬
下面对比一下在不同平台上提问同一个问题「hugo 怎么添加neodb短代码」得到的结果:
谷歌搜索只提供了一页搜索结果,这些搜索结果也跟我的问题十分强相关。
Bing给出了很多结果,超过十页了,具体多少我也没数。可以看到Bing的搜索结果里很多同一网站的内容并没有做合并,同一网站同一篇文章的中英文被分成了两条结果。后面几页的内容有些与我的问题已经没有太大的关系了(比如有一条搜索结果是如何部署hugo博客,只跟我的问题稍微沾点hugo的边)
百度出来的东西与我的问题不相关程度简直令人绝望、、、其他国内搜索引擎也不必多说,都差不多……
DuckDuckGo的搜索结果和Bing比较一致,有挺多重复和不太相关的内容需要人脑精细筛选。


Perplexity的好处是会列出它的参考来源,可以按图索骥找到原文获得更精确的背景描述和解决方案之类的。与之相反,ChatGPT则需要狠狠逼问才能问出它的参考来源。不过要注意的是,它们俩给出的答案在此情景下都是不能直接用的,作为搜索引擎使用的话也有点难用,所以还不如直接用搜索引擎。
如何搜索?#
使用精确的搜索关键字#
除了搜索平台以外,另一个影响搜索结果的重要因素就是搜索关键字。搜索引擎的工作原理包括三个阶段1:
- 抓取网络上的网页,并将其添加到已知网页列表中。
- 抓取网页后,Google 会尝试了解该网页的内容,包括处理和分析文字内容以及关键内容标记和属性。
- 用户输入查询时,搜索引擎会在索引中搜索匹配的网页,并返回它认为与用户的搜索内容最相关的优质结果;用户的位置、语言和设备(桌面设备或手机)等信息可能会影响搜索结果。
也就是说,如果想得到尽可能多的搜索结果,就要使输入的搜索关键字尽可能多地匹配网页。要是输入的搜索关键字太长,例如我在上面所使用的「hugo 怎么添加neodb短代码」,虽然这是个短句,但是能匹配到的内容相比「hugo neodb短代码」已经大大减少了;用后者这个关键字去搜索将会得到更多搜索结果;但要是精简过度,比如搜索「hugo neodb」则会得到很多完全不相关的搜索结果。
综上所述,搜索关键字可以极大影响搜索结果的质量,所以每次搜索时要用尽可能少的关键字同时尽可能精准地描述自己想得到的信息,一定要尽量避免「不能运行」、「程序报错」或者是「展示有问题」这类很模糊的用语。
此外,有一些小技巧可以进一步优化搜索结果,比如添加一些运算符(Operator)帮助搜索引擎理解你想要的信息2。
- 搜索完全匹配的词或短语:用英文双引号
""
将关键词括起来,例如hugo neodb "短代码"
表示搜索结果中必须要包含「短代码」这三个字。 - 搜索特定网站中的内容:使用
site:
运算符加上网址或域名,例如site:github.com hugo neodb短代码
表示搜索结果一定要来自GitHub网站。 - 排除不想要的关键词:使用减号
-
放在你不想包含的词前面,例如hugo neodb短代码 -Hi
表示搜索结果去掉包括「Hi」的内容。
此外,由于代码的世界太过于庞大,使用不同技术栈所需要的解决方法可能天差地别,因此一定要加上自己所使用的技术栈信息,例如使用了hugo博客框架的话,每次搜索都要加上「hugo」去筛选出自己所需要的结果;如果想进一步筛选出使用Blowfish主题的人所编写的教程,就需要搜索「hugo Blowfish」。
优先使用英文搜索#
绝大多数开源库的文档、bug解决方法和技术问题讨论帖都是先以英文发布的;甚至可以说几乎所有的报错信息都会是英文。因此,在遇到编程问题时,使用英文搜索能看到更多解法,而且遇到冷门问题时,用英文搜索也能提高找到答案的几率。
互联网技术的变化速度极其快,一些中文资料甚至可能已经失效但还在传播,英文搜索得到的结果也会更有时效性。我的个人经验是,一年至半年内写的教程一般不会有大问题,超过两年前的教程就要做好可能哪里会出问题的心理准备了,五年前的教程就可以直接关掉不需要看了…
学会看报错信息#
下面用我在装修博客时遇到的真实报错来举个例子,这是当时的报错信息(敏感信息已被我模糊):
render: failed to render pages: render of “/Users/xxx/Documents/nanako_blog/content/zh-cn/posts/spring-there-is-no-time-like-spring/index.md” failed: “/Users/xxx/Documents/nanako_blog/themes/blowfish/layouts/_default/single.html:92:13”: execute of template failed at <.Content>: error calling Content: “/Users/xxx/Documents/nanako_blog/content/zh-cn/posts/spring-there-is-no-time-like-spring/index.md:56:1”: failed to render shortcode “neodb”: failed to process shortcode: “/Users/xxx/Documents/nanako_blog/layouts/shortcodes/neodb.html:13:35”: execute of template failed at <transform.Unmarshal>: error calling Unmarshal: type template.TryValue not supported
粗略一看感觉报错信息好长啊,像一段天书,都有一点晕英文了()我们仔细看看这个报错信息,发现它主要分为五层内容:
failed to render pages: render of "/Users/xxx/Documents/nanako_blog/content/zh-cn/posts/spring-there-is-no-time-like-spring/index.md" failed
这是最外层的报错信息,意思是说这篇博客无法加载"/Users/xxx/Documents/nanako_blog/themes/blowfish/layouts/_default/single.html:92:13": execute of template failed at <.Content>
第二层报错信息是说single.html
(也就是 Hugo 用来渲染每一篇文章页面的模板文件),它在第 92 行第 13 列执行失败了,也就是{{ .Content }}
这一行代码执行失败,无法让文章内容显示出来execute of template failed at <.Content>: error calling Content: "/Users/xxx/Documents/nanako_blog/content/zh-cn/posts/spring-there-is-no-time-like-spring/index.md:56:1"
为什么无法展示文章内容呢,第三层报错信息进一步解释了原因,是因为index.md
(也就是放博客文章的Markdown内容文件)第56行出错了failed to render shortcode "neodb": failed to process shortcode: "/Users/xxx/Documents/nanako_blog/layouts/shortcodes/neodb.html:13:35"
第四层报错信息进一步地解释了index.md
第56行出错的原因——是因为neodb.html
这个短代码文件的第13行出错了execute of template failed at <transform.Unmarshal>: error calling Unmarshal: type template.TryValue not supported
最后一层报错信息,终于揭开了这个错误的真面目!意思是传进去的数据(某种变量)是 Hugo 模板里的TryValue
类型,而Unmarshal
不接受这种类型的数据。
程序的运行有点像俄罗斯套娃,稍微复杂一点的程序/技术都会采用多层嵌套结构,要么就是函数调用函数,又或者是组件使用组件,也可以是模块依赖模块。在编程里,有个通用原则是一个函数只做一件事,并且可以被其他地方复用,这一点就不仔细展开了,但是这么设计会让程序更有组织更有条理,开发更高效。因此,报错信息需要一层一层追踪,才能知道整个错误产生的链条是什么样的。
在这个例子里,博客依赖了 Hugo 模板,模板又用到了 shortcode 模块,shortcode 又用到了 transform 函数,层层递进。但是最重要的错误信息往往在最后一层,也就是error calling Unmarshal: type template.TryValue not supported
这一行内容。一般来说,这个最重要的报错信息可能会是其他更好理解的内容,比如说execute of template failed at <.Err>: can’t evaluate field Err in type resource.Resource: Resource.Err was removed in Hugo v0.141.0 and replaced with a new try keyword, see https://gohugo.io/functions/go-template/try/
这是另一个我遇到的报错,这里就说得很清楚,由于版本更新原因,不能用Err
来判断远程请求是否失败。
学会阅读报错信息后,就算自己还是不知道怎么解决这个错误,但是在搜索时就可以带上关键字搜出更多可能有用的内容。
如何更好使用AI?#
上文提到,不建议直接用AI取代搜索引擎的工作,所以在使用AI时最好自己已经搜出了一篇看起来合适的教程。还是用在博客里添加NeoDB短代码作为例子,我当时参考的博客是这个链接,遇到了一个问题是海报图片加载不出来,那么我向GPT提供教程中的代码和背景信息,GPT就能很快速地定位到问题代码并提出解决方案。
如果自己有一些想定制的需求,也可以直接问AI,这时候AI就很好用。
总结,在提供了具体的代码后,AI在Debug和微调代码功能/样式上都是十分好用的,但如果要让AI从0写一份代码,可用性就会大打折扣,Debug也会变得超级烦人!
还可以把直接把报错信息和报错代码直接提供给AI,但是我自己有遇到好几次AI提供的解决方案不生效的情况。
想找人求助?#
如果以上方式都没能解决自己的问题,需要找人求助的话,那么,请出每位程序员必读经典好文——《提问的智慧》(雾)
这篇文章虽然爹里爹气的,但是有一些精华值得吸收,其中最重要的就是如何描述自己的问题。
- 仔细、清楚地描述你的问题或 Bug 的症状。
- 描述问题发生的环境(机器配置、操作系统、应用程序、以及相关的信息),提供经销商的发行版和版本号(如:
Fedora Core 4
、Slackware 9.1
等)。- 描述在提问前你是怎样去研究和理解这个问题的。
- 描述在提问前为确定问题而采取的诊断步骤。
- 描述最近做过什么可能相关的硬件或软件变更。
- 尽可能地提供一个可以
重现这个问题的可控环境
的方法。
我个人觉得以上几项信息中,1、2、5是十分必须提供的,其他的就依情况而定。什么叫「仔细、清楚地描述你的问题」呢,举个例子,我之前遇到一个问题是【切换不同的页面时,顶部菜单中的语言切换按钮时有时无】。
如果我提问别人:「为什么我的博客的语言切换按钮时有时无呢?」,别人很难根据我这一句话就马上判断出是什么问题。如果TA之前遇到过同样问题,那么TA可能会有一些猜测,但还是要跟我询问更多信息后才能确认。p.s. 这么提问也有很大概率会引起别人的怒火(。)
此时,我应该提供的信息有:
- 截图。图上要能看出我的问题表现形式,「语言切换按钮怎么个时有时无法?」
- 代码。一般来说问题涉及到哪部分功能就提供哪部分代码,但是建议小白为了方便对方排查最好是直接给整个博客文件夹代码(因为小白可能判断不出来该给哪部分)
- 问题发生的环境。也就是告诉对方我用的是什么版本的Hugo、什么版本的Go等等,如果不知道怎么获取这些信息,可以问AI
- 自己所做过什么操作。最好说明一下这个问题是经过什么操作后出现的,如果自己已经排除了一些可能性,就最好还是提一下,可以节约对方的时间,也可以让对方更了解这个问题的情况
需要了解的编程知识#
天啊,终于进入正题了!本人写代码多年,深受知识诅咒的影响,如果哪里还讲得很不清楚,欢迎告诉我再补充哦!
博客类型#
静态博客#
所有的文章和页面,在用户写好之后就一次性生成成了普通网页(像 .html
文件那种)。这些网页不需要服务器处理内容,只需要放在网上,浏览器就能直接打开。像Hugo、Hexo和Jekyll等都是著名的静态博客框架。
动态博客#
每次有用户访问博客时,服务器都会现场生成网页——比如把文章内容从数据库里读出来,然后组合成一个页面再发给用户。比如Wordpress就是一个动态博客系统。
用印刷厂打比方,静态博客就是已经印好的书,任何人来都能直接拿起就看;动态博客则是每次有人想看书,印刷厂都现场开印。
Markdown#
静态博客生成器通常默认用 Markdown 写文章,Markdown是一种语法,它可以用纯文本的方式添加格式化元素。Markdown允许人们在写作时不需要考虑排版和格式问题,同时它也能与HTML语言混用来实现高级效果,具体可以参见Markdown教程,很详细地介绍了语法和用处,一学就会、一看就懂!
我推荐的Markdown编辑器有Obsidian(也很方便管理自己的博客文章)和Arya,后者是一个在线编辑器,因此要自己做好保存工作。
命令行工具#
不管用什么框架、什么主题,几乎都要用到命令行工具去操作博客。命令行工具(command-line interface,CLI)是一种使用键盘与操作系统交互的软件,与之相对的是图形用户界面(graphical user interface,GUI)。
我们日常操作电脑都是用的图形用户界面,图形用户界面将所有的电脑操作都形象展示了出来,简单易懂,但是对电脑来说效率十分低下。举个例子,这是文件夹的图形用户界面:
当我想打开Artificial Intelligence
这个文件夹时,我双击这个文件夹图标就能进入Artificial Intelligence
文件夹查看里面的内容。
同时我也可以用命令行工具实现同样的操作,如图:
所有操作系统(包括 Linux、macOS 和 Windows)均提供命令行工具,也各有不同的软件可以替代系统默认的命令行工具。但是Windows系统的命令和Mac、Linux系统都是不一样的,因此我在这里没有深入讲解要用什么命令以及怎么用,反正网上有很多资料一搜就出来了。
为什么一定要用命令行工具?因为静态博客工具(比如 Hexo、Hugo、Jekyll)本质上是一组命令,而不是一个有图形界面的软件。只有命令行工具可以与它们交互,告诉它们你想进行什么操作,没有命令行工具就无法控制这些博客生成工具。
想要了解更多的话,Windows用户可以搜索「windows 打开powershell」「windows powershell 教程」等;Mac用户可以搜索「mac 命令行工具」「mac 终端 教程」等;Linux用户,,,Linux用户应该不需要看这篇博客吧(
Git + GitHub#
Git是一个版本管理工具。简单来说,它帮你记录每一次对博客内容的修改,就像写作历史记录器。
GitHub是一个代码托管平台,你可以把用 Git 管理的博客内容上传到 GitHub 上,它就会一直保存、展示你的博客。(还有其他的代码托管平台,比如Gitee,但是GitHub是全球最大最常用的平台)
介绍Git和GitHub前,先说说如果没有 Git 和 GitHub要怎么搭建和发布静态博客呢?大概是以下步骤:
- 在自己的电脑上写好一篇 Markdown 博客
- 运行
hugo
命令,将Markdown文件生成为HTML网页到public/
文件夹,一个专门存放博客真正要发布到互联网上的那部分网站内容的地方 - 买一台服务器,因为需要一个服务器来存放自己的博客内容
- 想办法把
public/
那部分文件复制到新买的服务器里 - 在服务器里配置一番,让别人访问这个服务器时能展示自己的博客
而当用户配置好Git和GitHub后,它们会帮忙完成了其中大部分工作,使其精简为以下步骤:
- 在自己的电脑上写好一篇 Markdown 博客
- 用Git把新博客内容上传到GitHub仓库里
就没有了。配置得当的话(比如我用的Blowfish主题,在官方文档里就讲述了如何配置GitHub自动部署),只要GitHub检测到新更改,它可以自动更新部署博客内容,不需要用户操心。
搭建博客所需的Git和GitHub知识不算多,一般跟着教程上的内容去运行相应的命令就好了,遇到问题了就回到本博客第一章内容()也可以通过GitHub Desktop这个软件进行更新操作,这部分内容可以看冬不拉的教程。更多的内容也可以看Git教程和GitHub教程。
基本文件结构和配置#
这部分内容是我想写这个博客的醋啊!!!因为上次帮别人解决博客问题时,我发现编程小白确实不容易理解博客里的文件结构分别有什么用,教程一般也不会讲得那么细,所以我打算写一篇讲一下。
搭建博客#
由于大家参考的教程不同,安装主题的方式也分好几种,本文主要介绍使用Git子模块安装的方式(我也最推荐这种安装方式,因为切换主题和更新主题都很方便)。这里可以先不理解原理,直接按照文档进行操作即可。
什么是Git子模块?
子模块(submodule)是 Git 中的一个功能,允许用户在一个 Git 仓库里引用另一个 Git 仓库。用子模块的方式引用主题,就是“链接”而不是“复制”这个主题的代码。
这个安装方式的特点就是博客目录下面会出现一个themes
文件夹(使用Hugo模块安装的话则没有这个themes
文件夹),如图
如果想安装多个主题,就用同样的方式安装,其余主题也会出现在themes
文件夹下方;切换主题时只需要修改hugo.toml
里的这一行即可:
themes
里面的文件!!!如果有任何想自定义覆盖的部分,在同样目录下创建一个新文件即可。比如你想覆盖的原始模板路径是:themes/ananke/layouts/_default/single.html
,那么复制到自己的Hugo项目的路径就是:layouts/_default/single.html
文件结构#
Hugo博客的文件夹结构应该不会差很多,但是具体还是要看自己所使用主题的官方文档。以我自己的博客(也就是Blowfish主题)为例,整个博客的文件夹结构如图:


其中在content
文件夹里我放了两种语言,这两种语言的文件目录要保持一致(比如都要有友链页面,不要只记得在中文目录里加,而忘记在英文目录里加)不然语言切换按钮就会时有时无(完美callback了前面的内容!)
自定义布局#
为了更好地帮助大家理解文件结构,我举两个实际的例子吧。
如何在博客里添加友链页面#
先在菜单按钮定义文件里加上友链按钮:
如果 Hugo 找不到任何其他模板来渲染特定的内容,它会在layouts/_default
目录中查找。为了展示我的友链,我创建了一个layouts/_default/friends.html
文件,里面的内容是我从Blowfish主题里复制过来的单页布局。
此处,文件名要和menus.zh-cn.toml
中定义的名字一致,如果某一处不小心拼写错误了没对上,是访问不到此页面的。
最后就是创建friends.md
页面存放我的友链页面要展示的具体内容了。
如何在原主题的基础上自定义?#
Blowfish提供了一个叫「色板」的短代码功能,我想使用的时候发现有一点我不太喜欢——它展示的颜色没有边框。我就想稍作修改,在颜色周围加一圈边框。
我先找到原主题中的色板定义文件,复制这个文件(内容如图)
再把这个文件粘贴到我自己博客目录的同一个位置(比如看图上文件路径,~/Documents/nanako_blog/
不用管,我是把themes
里的layouts/shortcodes/swatches.html
复制到了我自己博客的layouts/shortcodes/swatches.html
),最后在复制出来的新文件里的代码加上边框:
这样就完成啦!
Hugo 会按照以下顺序查找模板文件:
layouts/(我自己的博客目录)
↓
themes/xxx/layouts/(主题目录)
所以只要复制主题里 layouts/
的某个文件到你项目的 layouts/
中并修改它,就能覆盖默认主题的模板样式,而且不影响原主题代码。
如果对更多Hugo目录结构内容感兴趣,可以查看这篇博客。
总结#
想写这篇博客的原因就是想介绍一下博客的目录结构,让大家对自己要修改的内容位置在哪有个概念,结果没想到写了这么多杂七杂八的最后这么长()希望这篇博客真的对大家有帮助呢!