Jekyll 使用技巧
2017-04-19 tech jekyll 29 mins 2 图 10338 字
这篇文章转载自文末的三篇引用。
简介
什么是Jekyll
Jekyll 是一个基于 Ruby 的静态网站生成器,而 gem
是 Ruby 的包管理器。bundle
是一个用于管理项目 gem 依赖关系的工具,它通过 Gemfile
和 Gemfile.lock
文件来跟踪和安装依赖项。
简单来说,gem
是 Ruby 的全局包管理器,而 bundle
是用于管理项目级别的依赖关系的工具。
在使用 Jekyll 时,通常建议使用 bundle
来管理项目的 gem 依赖,以确保每个项目都有一致的 gem 环境。这样可以防止不同项目之间的 gem 版本冲突,确保项目能够正确运行。
安装
首先,你得有 Ruby。对于 Mac 用户,可以使用 Homebrew 安装。
brew install ruby
然后:
$ gem install jekyll
Bundler
Jekyll 3.3.0 之后开始采用 Bundler 方式运行。安装时,需要同时安装 Bundler:
$ gem install jekyll bundler
所以所有命令可能也需要使用 Bundler:
$ bundle exec jekyll serve
命令
使用 jekyll new
创建新站点
$ jekyll new my-jekyll-site
也可以:
$ mkdir my-jekyll-site
$ cd my-jekyll-site
$ jekyll new .
使用 jekyll serve
在本地运行站点
以下三种使用方式是等价的:
$ jekyll serve
$ jekyll server
$ jekyll s
通过 http://localhost:4000
进行访问。
使用 jekyll build
生成站点
以下两种使用方式是等价的:
$ jekyll build
$ jekyll b
通过 --destination
指定目标路径:
$ jekyll build --destination=/path/to/site
使用 jekyll new-theme
创建主题
$ jekyll new-theme my-theme
修改 Gemfile之后重新install
bundle install
基础
目录结构
一个基本的 Jekyll 站点目录结构:
.
├── _config.yml
├── _data
| └── members.yml
├── _drafts
| ├── begin-with-the-crazy-ideas.md
| └── on-simplicity-in-technology.md
├── _includes
| ├── footer.html
| └── header.html
├── _layouts
| ├── default.html
| └── post.html
├── _posts
| ├── 2007-10-29-why-every-programmer-should-play-nethack.md
| └── 2009-04-26-barcamp-boston-4-roundup.md
├── _sass
| ├── _base.scss
| └── _layout.scss
├── _site
├── .jekyll-metadata
└── index.html # 也可以是 index.md
- _config.yml
- Jekyll 站点的总配置文件,有很多选项也可以通过命令行方式指定。
- _drafts
- 未发布的草稿,文件名不需要带有日期。
- _includes
- 代码片段,可以通过
include
进行引用。
- 代码片段,可以通过
- _layouts
- 布局。布局文件可以被继承,
{{ content }}
用于表示被继承者的内容。
- 布局。布局文件可以被继承,
- _posts
- 文件,命名需要以日期开头:如
2016-12-01-my-article.md
。
- 文件,命名需要以日期开头:如
- _sass
- sass 文件,可以通过插件完成编译。也可以选择引入原生 CSS,或者 Less 等。
- _site
- 目标文件,建议加入到
.gitignore
中。
- 目标文件,建议加入到
- index.html/index.md
- 首页
_config.yml
_config.yml
是整个站点的整体配置,以下是所有配置项和默认值:
# Where things are
source: .
destination: ./_site
plugins_dir: _plugins
layouts_dir: _layouts
data_dir: _data
includes_dir: _includes
collections:
posts:
output: true
# Handling Reading
safe: false
include: [".htaccess"]
exclude: ["node_modules", "vendor/bundle/", "vendor/cache/", "vendor/gems/", "vendor/ruby/"]
keep_files: [".git", ".svn"]
encoding: "utf-8"
markdown_ext: "markdown,mkdown,mkdn,mkd,md"
# Filtering Content
show_drafts: null
limit_posts: 0
future: false
unpublished: false
# Plugins
whitelist: []
gems: []
# Conversion
markdown: kramdown
highlighter: rouge
lsi: false
excerpt_separator: "\n\n"
incremental: false
# Serving
detach: false
port: 4000
host: 127.0.0.1
baseurl: "" # does not include hostname
show_dir_listing: false
# Outputting
permalink: date
paginate_path: /page:num
timezone: null
quiet: false
verbose: false
defaults: []
liquid:
error_mode: warn
# Markdown Processors
rdiscount:
extensions: []
redcarpet:
extensions: []
kramdown:
auto_ids: true
footnote_nr: 1
entity_output: as_char
toc_levels: 1..6
smart_quotes: lsquo,rsquo,ldquo,rdquo
input: GFM
hard_wrap: false
footnote_nr: 1
Front Matter
Jekyll 整个站点的配置是站点根目录下的 _config.yml
文件,而 _layout
, _posts
等目录下的文件中也可以有自己的变量。文件头部的 yaml
配置被称作 Front Matter。
Front Matter 默认值
可以使用 defaults
设置一个路径下 Front Matter 默认值。
defaults:
- scope:
path: ""
type: weekly
values:
layout: weekly
title: 技术周刊
忽略文件
exclude
用于忽略文件或文件夹,其中 _config.yml
和以.
开头的文件或文件夹都会被自动忽略。后续版本,node_modules
等文件夹也被隐式忽略了(参考 _config.yml 章节)。
exclude:
- Gemfile
- Gemfile.lock
- README.md
- LICENSE
分页
Jekyll 没有内置分页功能,而是提供了一个分页插件 jekyll-paginate
。jekyll-paginate
仅在特定的默认条件下生效,如果你对网站结构有自己的一套,jekyll-paginate
可能是无法满足需求的。
限制如下:
- 分页功能必须在 HTML 格式文件中调用,如:
index.html
- 必须使用默认的链接格式
permalink
如果想继续使用,请详细阅读 http://jekyllrb.com/docs/pagination/。这是一个复杂的问题!
文章摘要
Jekyll 提供了文章摘要摘取功能,通过 post.excerpt
就可以获得摘要内容。
我们也可以设置摘取摘要的分隔符:
excerpt_separator: <!--more-->
评论
由于是静态站点,我们没发内建评论系统,因此需要引入一些纯前端就可以使用的评论系统。国外推荐:disqus,国内推荐:duoshuo。
Page
可以认为,不在 _post
目录下的页面都是 Page 而不是 Post,其它方面区别不大。
Collection
并不是每个页面都是独立“页面”和以日期为顺序的“博文”,因此 Jekyll 引入了 Collection。Collection 可以根据路径定义一类具有相同属性的页面集合。Collection 也可以通过 Front Matter 设定默认值。
Data
Data 相当于动态页面中的数据库,Jekyll Data 支持 yaml
, json
, CSV
三种格式,可以通过 site.data
直接访问。
例如:
团队成员有 Fa, Li, Zhang 三人,于是我们在默认路径 _data
创建一个数据文件 member.yml
:
- name: Fa
- name: Li
- name: Zhang
在页面中显示团队成员列表:
{% for member in site.data.member %}
<ul>
<li>{{ member.name }}</li>
</ul>
{% endfor %}
Liquid 模板
什么是 Liquid?
Liquid 是一个开源模版语言,由电商公司 Shopify 实现,用 Ruby 编写。Shopify 自己使用 Liquid 来构建自己电商网站模板生态。
详细文档请参考 https://shopify.github.io/liquid/。
Jekyll 实用 Liquid 作为模版引擎,构建页面。
变量
<title>
{{ page.title }}
</title>
其中,Jekyll 预设了 site
, layout
, page
, content
四个全局变量。
逻辑判断
Liquid 的逻辑判断跟 Ruby 完全一致。
- 常见语言中的
if
,else if
,else
在 Liquid 中的对应是if
,elsif
,else
。同时,Liquid 也可以使用 Ruby 特有的unless
。 - 常见语言中的
switch
,case
在 Liquid 中的对应是case
,when
。
为了简单,只以 if
为例:
{% if page.disable_syntax_highlight != true %}
<link rel="stylesheet" href="{{ site.assets }}/css/zenburn.css">
{% endif %}
遍历
在 Liquid 中可以通过 for
in
语法遍历数组,并且支持一般语言循环中的 continue
和 break
。
除此之外,还可以使用 offset
和 limit
控制遍历范围,通过 reversed
进行倒序。
{% for post in site.posts reversed %}
<a href="{{ post.permalink }}">{{ post.title }}</a>
{% endfor %}
详见 https://shopify.github.io/liquid/tags/iteration/
赋值
使用 assign
进行赋值:
{% assign my_variable = false %}
使用 capture
进行捕捉赋值:
{% capture my_variable %}
I am being captured.
{% endcapture %}
Liquid Filters
Liquid Filters 是一种针对 Liquid 中变量的过滤器,语法是:
{{ var | filter: "param" }}
除去 Liquid 自身丰富的过滤器之外,Jekyll 还额外扩展了一些实用的:
cgi_escape
url_escape
xml_escape
- 对变量进行相应的 escape
markdownify
scssify
sassify
jsonify
- 对变量内容的格式转换
where
where_exp
group_by
sort
- 对变量数据的查询排序等操作
详见 http://jekyllrb.com/docs/templates/#filters
site全局根结点
在全局根结点site中有 site.tags.TAG 和 site.categories.category.CATEGORY 变量,可以列出所有拥有TAG标签或者CATEGORY的文章的列表(这里的变量只能写英文)。 另外site.[CONFIGURATION_DATA]使得所有在_config.yml中的数据都能够通过site变量调用。
循环
和平常的解释性语言很像
{ % for post in site.posts % }
<a href="{ { post.url } }">{ { post.title } }</a>
{ % endfor % }
if判断
注意逻辑“与或”分别是and
,or
{ % if user % }
Hello
{ % endif % }
# Same as above
{ % if user != null % }
Hello
{ % endif % }
{ % if user.name == 'tobi' % }
Hello tobi
{ % elsif user.name == 'bob' % }
Hello bob
{ % endif % }
{ % if user.name == 'tobi' or user.name == 'bob' % }
Hello tobi or bob
{ % endif % }
{ % if user.name == 'bob' and user.age > 45 % }
Hello old bob
{ % endif % }
{ % if user.name != 'tobi' % }
Hello non-tobi
{ % endif % }
# Same as above
{ % unless user.name == 'tobi' % }
Hello non-tobi
{ % endunless % }
# Check for the size of an array
{ % if user.payments == empty % }
you never paid !
{ % endif % }
{ % if user.payments.size > 0 % }
you paid !
{ % endif % }
{ % if user.age > 18 % }
Login here
{ % else % }
Sorry, you are too young
{ % endif % }
# array = 1,2,3
{ % if array contains 2 % }
array includes 2
{ % endif % }
# string = 'hello world'
{ % if string contains 'hello' % }
string includes 'hello'
{ % endif % }
自动生成摘要
{ % for post in site.posts % }
{ { post.url } } { { post.title } }
{ { post.excerpt | remove: 'test' } }
{ % endfor % }
删除指定文本
remove 可以删除变量中的指定内容
{ { post.url | remove: 'http' } }
删除 html 标签
{ { post.excerpt | strip_html } }
代码高亮并且显示行数
{ % highlight ruby linenos % }
\# some ruby code
{ % endhighlight % }
获得数组的大小
{ { array | size } }
赋值
{ % assign index = 1 % }
搜索指定key
# Select all the objects in an array where the key has the given value.
{ { site.members | where:"graduation_year","2014" } }
排序
{ { site.pages | sort: 'title', 'last' } }
转换成JSON
{ { site.data.projects | jsonify } }
把一个对象变成一个字符串
{ { page.tags | array_to_sentence_string } }
单词的个数
{ { page.content | number_of_words } }
得到数组指定范围的结果集
{ % for post in site.posts limit:20 % }
插件
插件简介
Jekyll 支持使用插件进行扩展,插件的类型分为:Generators、Converters、Commands、Hooks、Liquid Tag、Liquid Filter 等。
如果希望开发插件,请参考 http://jekyllrb.com/docs/plugins/
使用插件
-
基于 Gem 的方式
对于已经发布到 RubyGems 的插件,推荐使用这种方式。只需要在
_config.yml
中gems
字段加入相应插件名称即可。 -
基于本地文件
对于没有发布的插件,可以在
_plugins
文件夹中直接引入*.rb
Ruby 源文件。
常用插件
Jekyll Watch
Jekyll “必备”的插件,因为这是 Jekyll 程序的依赖,只是因为程序结构设计被剥离成了插件。它在本地预览时,提供文件变更的自动更新,让我们每次刷新都能自动看到最新的内容。
Jekyll Watch 是自动开启的:
$ jekyll serve --watch
Jekyll Compose
安装了 Jekyll Compose 后,Jekyll 会额外提供一些命令,便于发布管理博文。
创建草稿:
$ jekyll draft
创建新博客:
$ jekyll post
创建新博客:
$ jekyll page
发布草稿:
$ jekyll publish
撤销发布:
$ jekyll unpublish
Jekyll Admin
Jekyll Admin 是一个 CMS 风格的图形化后台管理插件,可以在本地给用户提供服务。
Jekyll SEO Tag
Jekyll SEO Tag 帮你生成一大堆 Meta 标签。
Jemoji
你可以通过 Jemoji 在 Jekyll 生成的网站中,加入自己 Emoji 表情。
Emoji 语法采用 GitHub 的语法风格。
Jekyll Mentions
Jekyll Mentions 允许你在文章中直接“@” GitHub 或其它网站用户。
Jekyll Feed
你可以通过 Jekyll Feed 在 Jekyll 生成的网站中,生成 RSS 源。
Jekyll Import
Jekyll Import 支持从一些国外的主流站点导入博文,如 Blogger, WordPress 和 Tumblr 等,同样也支持 RSS 和 CSV 等数据格式导入。
Jekyll Archives
Jekyll Archives 用于生成带标签和分类的『存档』页面。
Jekyll Redirect From
Jekyll Redirect From 提供页面跳转功能,比较简单,也可以自行通过 JavaScript 实现。
GitHub Pages
创建个人主页
创建一个名为 your-github-username.github.io
的 Repo,your-github-username
是你的用户名。
只需在 Repo 中设置 GitHub Pages 的 Source,就可以开启 GitHub Pages,支持 master
, gh-pages
, master
中 /docs
文件夹三种 Source。
在 GitHub Pages 只可以使用部分插件
由于安全性等原因的考虑,在 GitHub Pages 平台上只能使用白名单中的 7 个 Jekyll 插件。它们分别是:Jekyll Sitemap, Jekyll SEO Tag, github-metadata, Jekyll Feed, Jekyll Redirect From, Jemoji 和 Jekyll Mentions。
详见 https://help.github.com/articles/adding-jekyll-plugins-to-a-github-pages-site/。
GitHub Pages 上的 Jekyll 只支持 kramdown
从 2016 年 5 月 1 日起,GitHub Pages 只支持 kramdown 作为 Markdown 引擎。
详见 https://github.com/blog/2100-github-pages-now-faster-and-simpler-with-jekyll-3-0。
在根目录下创建 .nojekyll
文件可以跳过 Jekyll 解析
GitHub Pages 支持 Jekyll 或者原始文件。最初 GitHub Pages 只支持 Jekyll,后来 GitHub 允许在 Repo 根目录下添加 .nojekyll
跳过解析。
详见 https://github.com/blog/572-bypassing-jekyll-on-github-pages。
你可以使用自己的域名
在 Source 的根路径下,创建 CNAME
写入域名,然后把 DNS 解析到 GitHub Pages 的 IP:192.30.252.153
和192.30.252.154
。
详见 https://help.github.com/articles/using-a-custom-domain-with-github-pages/
你也可以为账号下任意项目创建独立的项目页面
任何一个项目的 Repo,都可以开启这个项目的 GitHub Pages。开启方式同个人主页。
如项目:crispgm/gsm,设置完成后,就可以通过 https://crispgm.github.io/gsm/ 进行访问。
你可以通过 site.github
获得 Repo 的信息
由上面所说的 github-metadata 提供服务,通过 GitHub API 获取 Repo 的信息。当然,在本地环境下,也可以通过手动安装 github-metadata 来使用。
私有 Repo 也可以开启 GitHub Pages
GitHub 的付费用户建立的私有项目 Private Repo,也可以开启 GitHub Pages。
GitHub Pages 无法在使用 gh-pages
分支作为源的情况下关闭
有些奇怪的设定,真想关闭直接删除掉,在 Source 选择 None 就好。