强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第14章:最佳实践

第14章:最佳实践

14.1 性能优化

构建性能

# 查看构建性能分析
bundle exec jekyll build --profile

# 输出示例:
# Filename                           | Count |  Bytes |  Time
# -----------------------------------+-------+--------+------
# _layouts/default.html              |   150 | 960000 | 2.1s
# _posts/2025-01-15-post.md          |     1 |   5000 | 0.3s
# _includes/header.html              |   150 | 120000 | 0.8s

增量构建

# 增量构建(只处理修改的文件)
bundle exec jekyll build --incremental

# 或在 _config.yml 中配置
incremental: true

注意事项

  • 增量构建可能不总是正确更新(特别是涉及依赖时)
  • 生产构建建议使用全量构建
  • 开发时使用增量构建加快反馈速度

内容优化

优化项方法效果
减少 Liquid 循环缓存循环结果减少模板处理时间
简化 include减少嵌套深度降低渲染复杂度
精简数据文件只加载需要的数据减少内存占用
排除无用文件exclude: 配置减少文件扫描
# _config.yml
exclude:
  - Gemfile
  - Gemfile.lock
  - node_modules
  - README.md
  - vendor
  - scripts
  - "*.config.js"
  - ".github"

14.2 SEO 优化

基础 SEO 配置

# _config.yml
title: "My Blog"
description: "A tech blog about web development"
url: "https://blog.example.com"
author: "Zhang San"

plugins:
  - jekyll-seo-tag
  - jekyll-sitemap
  - jekyll-feed
<!-- _includes/head.html -->
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  {% seo %}
  {% feed_meta %}
  <link rel="canonical" href="{{ page.url | absolute_url }}">
</head>

文章 SEO 最佳实践

---
title: "Jekyll SEO 完全指南"
description: "详细介绍如何优化 Jekyll 站点的搜索引擎排名"
date: 2025-01-15
last_modified_at: 2025-02-01
image: /images/posts/jekyll-seo.jpg
keywords: [jekyll, seo, 静态站点]
canonical_url: "https://blog.example.com/jekyll-seo-guide/"
robots: "index, follow"
---

Open Graph 标签

<!-- _includes/og-tags.html -->
<meta property="og:title" content="{{ page.title | default: site.title }}">
<meta property="og:description" content="{{ page.description | default: site.description | strip_html | truncatewords: 30 }}">
<meta property="og:type" content="{% if page.layout == 'post' %}article{% else %}website{% endif %}">
<meta property="og:url" content="{{ page.url | absolute_url }}">
<meta property="og:site_name" content="{{ site.title }}">
{% if page.image %}
  <meta property="og:image" content="{{ page.image | absolute_url }}">
{% else %}
  <meta property="og:image" content="{{ '/images/default-og.png' | absolute_url }}">
{% endif %}
<meta property="og:locale" content="{{ site.lang | default: 'zh_CN' }}">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="{{ page.title | default: site.title }}">
<meta name="twitter:description" content="{{ page.description | default: site.description }}">
{% if page.image %}
  <meta name="twitter:image" content="{{ page.image | absolute_url }}">
{% endif %}

结构化数据(JSON-LD)

<!-- _includes/structured-data.html -->
{% if page.layout == 'post' %}
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "{{ page.title }}",
  "description": "{{ page.description }}",
  "datePublished": "{{ page.date | date_to_xmlschema }}",
  "dateModified": "{{ page.last_modified_at | default: page.date | date_to_xmlschema }}",
  "author": {
    "@type": "Person",
    "name": "{{ page.author | default: site.author }}"
  },
  "publisher": {
    "@type": "Organization",
    "name": "{{ site.title }}",
    "logo": {
      "@type": "ImageObject",
      "url": "{{ '/images/logo.png' | absolute_url }}"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "{{ page.url | absolute_url }}"
  }
  {% if page.image %}
  ,"image": "{{ page.image | absolute_url }}"
  {% endif %}
}
</script>
{% endif %}

sitemap.xml

---
layout: null
permalink: /sitemap.xml
---
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  {% for page in site.pages %}
    {% unless page.sitemap == false %}
    <url>
      <loc>{{ page.url | absolute_url }}</loc>
      <lastmod>{{ page.last_modified_at | default: page.date | date_to_xmlschema }}</lastmod>
      <changefreq>{% if page.layout == 'post' %}monthly{% else %}weekly{% endif %}</changefreq>
      <priority>{% if page.url == '/' %}1.0{% elsif page.layout == 'post' %}0.8{% else %}0.5{% endif %}</priority>
    </url>
    {% endunless %}
  {% endfor %}
</urlset>

robots.txt

# static/robots.txt
User-agent: *
Allow: /
Sitemap: https://blog.example.com/sitemap.xml

Disallow: /assets/
Disallow: /_site/

14.3 图片优化

响应式图片

<!-- _includes/responsive-image.html -->
{% assign default_sizes = "320,640,960,1280" | split: "," %}
{% assign sizes = include.sizes | default: default_sizes %}

<picture>
  {% for size in sizes %}
    <source
      media="(max-width: {{ size }}px)"
      srcset="{{ include.src | replace: '.', '-' | append: '-' | append: size | append: '.webp' | relative_url }}">
  {% endfor %}
  <img
    src="{{ include.src | relative_url }}"
    alt="{{ include.alt }}"
    loading="lazy"
    width="{{ include.width }}"
    height="{{ include.height }}">
</picture>

构建时图片处理插件

# Gemfile
gem "jekyll-responsive-image"
# _config.yml
plugins:
  - jekyll-responsive-image

responsive_image:
  template: _includes/responsive-image.html
  default_quality: 80
  sizes:
    - width: 320
    - width: 640
    - width: 960
    - width: 1280
  output_path_format: assets/images/resized/%{width}/%{filename}

图片压缩工作流

# 使用 imagemin 批量压缩
npx imagemin static/images/**/* --out-dir=assets/images --plugin=pngquant --plugin=mozjpeg

# 使用 Squoosh CLI
npx @squoosh/cli --webp '{quality:80}' static/images/*.jpg

图片最佳实践

实践说明
使用 WebP比 JPEG 小 25-35%
懒加载loading="lazy" 属性
指定尺寸避免布局偏移(CLS)
响应式使用 <picture>srcset
CDN使用图片 CDN(如 Cloudinary)
压缩构建时压缩,保持质量

14.4 安全最佳实践

HTTP 安全头

# nginx.conf
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline';" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;

依赖安全

# 检查 Gem 依赖漏洞
bundle audit check --update

# 定期更新依赖
bundle update

# 锁定版本
# Gemfile.lock 应该提交到 Git

14.5 工作流最佳实践

Git 分支策略

main           ← 生产分支,自动部署
├── dev        ← 开发分支
│   ├── feature/new-post    ← 新文章
│   ├── feature/redesign    ← 设计改版
│   └── fix/typo            ← 修复

提交信息规范

feat: 添加新文章《Jekyll 最佳实践》
fix: 修复移动端导航菜单问题
style: 调整代码块配色
docs: 更新 README
chore: 升级 Jekyll 到 4.3.3
perf: 优化图片加载性能

自动化工作流

# .github/workflows/automation.yml
name: Site Automation

on:
  schedule:
    - cron: '0 0 * * 0'  # 每周日

jobs:
  update-deps:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'
      - run: bundle update
      - name: Create PR
        uses: peter-evans/create-pull-request@v5
        with:
          title: "chore: weekly dependency update"
          branch: chore/dep-update

  check-links:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: '3.2'
          bundler-cache: true
      - run: |
          bundle exec jekyll build
          bundle exec htmlproofer ./_site --allow-hash-href

14.6 从其他平台迁移

从 WordPress 迁移

# 1. 导出 WordPress 数据
# 安装 WordPress 导出插件
# Tools > Export > All content

# 2. 使用 Jekyll 导入工具
gem install jekyll-import
gem install hpricot

# 3. 执行导入
ruby -r rubygems -r hpricot -r jekyll-import -e '
  JekyllImport::Importers::WordPress.run({
    "dbname"   => "wordpress_db",
    "user"     => "root",
    "password" => "",
    "host"     => "localhost",
    "prefix"   => "wp_",
    "clean_entities" => true
  })
'

从 Hexo 迁移

# Hexo 和 Jekyll 结构相似,迁移较简单

# 1. 复制文章
cp -r hexo/source/_posts/ jekyll/_posts/

# 2. 调整 Front Matter
# Hexo 使用 <!-- more --> 作为摘要分隔
# Jekyll 默认使用 excerpt_separator

# 3. 修改模板语法
# Hexo: {% blockquote %}  → Jekyll: <blockquote>
# Hexo: {% codeblock %}   → Jekyll: ```代码块```

从 Hugo 迁移

# Hugo 和 Jekyll 的主要差异:
# 1. 模板语言(Go Template vs Liquid)
# 2. 目录结构
# 3. Front Matter 字段名

# 迁移步骤:
# 1. 复制内容
cp -r hugo/content/post/ jekyll/_posts/

# 2. 转换 Front Matter
# Hugo: title, date, draft, tags, categories
# Jekyll: title, date, published, tags, categories

# 3. 转换模板
# {{ .Title }}        → {{ page.title }}
# {{ .Content }}      → {{ content }}
# {{ range .Pages }}  → {% for page in site.pages %}

迁移检查清单

## 迁移后检查

- [ ] 所有文章已正确导入
- [ ] Front Matter 格式正确
- [ ] 图片路径已更新
- [ ] 内部链接有效
- [ ] 分类和标签完整
- [ ] 永久链接与原站一致(或已配置重定向)
- [ ] SEO 元标签完整
- [ ] sitemap.xml 生成正确
- [ ] 旧 URL 重定向配置
- [ ] RSS feed 地址更新
- [ ] 评论系统迁移(如需要)
- [ ] 分析代码已添加

14.7 项目结构最佳实践

my-jekyll-site/
├── .github/
│   └── workflows/          # CI/CD 工作流
├── _config.yml             # 主配置
├── _config_dev.yml         # 开发环境覆盖
├── _data/                  # 数据文件
│   ├── navigation.yml
│   └── authors.yml
├── _drafts/                # 草稿
├── _includes/              # 可复用片段
│   ├── head.html
│   ├── header.html
│   ├── footer.html
│   ├── seo.html
│   └── analytics.html
├── _layouts/               # 布局模板
│   ├── default.html
│   ├── post.html
│   ├── page.html
│   └── home.html
├── _plugins/               # 自定义插件
├── _posts/                 # 文章
│   └── 2025/
├── _sass/                  # Sass 源文件
│   ├── _variables.scss
│   ├── _mixins.scss
│   ├── _base.scss
│   └── _components.scss
├── assets/                 # 静态资源
│   ├── css/
│   ├── js/
│   ├── images/
│   └── fonts/
├── pages/                  # 独立页面
├── Gemfile
├── Gemfile.lock
├── .gitignore
├── .dockerignore
├── Dockerfile
├── docker-compose.yml
├── netlify.toml            # 或 vercel.json
├── README.md
└── LICENSE

14.8 文章写作规范

Front Matter 模板

---
title: "文章标题"
date: 2025-01-15 10:30:00 +0800
last_modified_at: 2025-02-01
layout: post
permalink: /blog/article-slug/
categories: [技术, Jekyll]
tags: [tutorial, beginner]
description: "一句话描述文章内容"
author: "作者名"
image: /images/posts/article-slug.jpg
excerpt_separator: 



comments: true
toc: true
---

Markdown 写作规范

# 一级标题(仅用于文章标题)

## 二级标题(主要章节)

### 三级标题(子章节)

正文内容,中文与英文之间加空格。

> 引用内容

**加粗***斜体*

- 列表项1
- 列表项2

```ruby
# 代码块标注语言
puts "Hello, World!"
表头1表头2
内容1内容2

链接文本

图片描述


---

## 14.9 备份与恢复

### Git 备份

```bash
# 定期推送到远程仓库
git add .
git commit -m "backup: $(date +%Y-%m-%d)"
git push origin main

完整备份脚本

#!/bin/bash
# backup.sh

BACKUP_DIR="/backups/jekyll"
DATE=$(date +%Y%m%d_%H%M%S)
SITE_DIR="/opt/jekyll-site"

# 创建备份
mkdir -p "$BACKUP_DIR"
tar -czf "$BACKUP_DIR/jekyll_backup_$DATE.tar.gz" \
    --exclude='_site' \
    --exclude='.jekyll-cache' \
    --exclude='vendor' \
    -C "$(dirname $SITE_DIR)" \
    "$(basename $SITE_DIR)"

# 保留最近 30 天的备份
find "$BACKUP_DIR" -name "*.tar.gz" -mtime +30 -delete

echo "Backup completed: jekyll_backup_$DATE.tar.gz"

14.10 监控与分析

Google Analytics 集成

<!-- _includes/analytics.html -->
{% if jekyll.environment == "production" and site.google_analytics %}
<script async src="https://www.googletagmanager.com/gtag/js?id={{ site.google_analytics }}"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', '{{ site.google_analytics }}');
</script>
{% endif %}

性能监控

# _config.yml
google_analytics: "G-XXXXXXXXXX"

# 仅在生产环境启用
# 在 _layouts/default.html 中
{% include analytics.html %}

14.11 扩展阅读


本章小结

要点说明
性能优化增量构建、排除无用文件、优化模板
SEOjekyll-seo-tag、结构化数据、sitemap
图片优化WebP、懒加载、响应式、压缩
安全HTTP 安全头、依赖审计
工作流Git 分支策略、提交规范、自动化
迁移WordPress/Hugo/Hexo 迁移工具和步骤
备份Git + 定期备份脚本

恭喜!你已完成 Jekyll 静态站点完全教程的全部 14 章内容。

回到目录:教程概览