Posted on :: Updated on :: Tags: ,

hello zola/Rust!

年后第二天上班,给自己定了一个目标,今年要从c++过渡到rust,恰巧发现阿里云续费还是99一年,果断续费一年,又恰巧在看GitHub热点项目时发现了zola

仔细对比了hugo和zola(其实是刚开工比较闲。。。),考虑到zola的rust属性,最后选择了zola(其实我也想搭建一个hugo的网站对比一下,但是有点懒)。

如果没有意外,这篇博客会成为流水账,记录我是如何安装zola,设置zola,运行demo,如何修改某些地方,如何添加其他功能。事实上我确实就是在不知不觉中这样写的,但是第三天吃完午饭脑子里突然蹦出一句话:博客不是流水账!!!

zola原理探究

zola源码主要存放在src和components中,其中components是核心底层代码,每个子文件夹是一个功能模块,具体含义可以问gpt,我们的目标是探究基于rust的静态网页生成器的核心功能和原理。因此我们选用一个核心功能来学习:site。

build.rs

//src/cmd/build.rs
let mut site = Site::new(root_dir, config_file)?;
site.load()?;
site.build()

Site模块是负责整个网站生成的接口

site

site结构体:

pub struct Site {
    // 站点的基础路径
    pub base_path: PathBuf,
    // 解析后的配置文件参数,例如base_url,themes等
    pub config: Config,
    // 用于渲染模板的 Tera 实例
    pub tera: Tera,
    // 用于处理图像的处理器,采用 Arc 和 Mutex 以支持多线程安全
    imageproc: Arc<Mutex<imageproc::Processor>>,
    // 如果启用了实时重载功能,存储其端口号
    pub live_reload: Option<u16>,
    // 生成的静态文件输出路径
    pub output_path: PathBuf,
    // 内容文件的路径,通常是存放 Markdown 文件的目录
    content_path: PathBuf,
    // Sass 文件的路径,用于样式表的编译。
    pub sass_path: PathBuf,
    // 静态资源的路径,如图片、JavaScript 文件等。
    pub static_path: PathBuf,
    // 模板文件的路径。
    pub templates_path: PathBuf,
    // 站点的分类和标签等分类法。
    pub taxonomies: Vec<Taxonomy>,
    /// A map of all .md files (section and pages) and their permalink
    /// We need that if there are relative links in the content that need to be resolved
    pub permalinks: HashMap<String, String>,
    /// Contains all pages and sections of the site
    pub library: Arc<RwLock<Library>>,
    /// Whether to load draft pages
    include_drafts: bool,
    build_mode: BuildMode,
    shortcode_definitions: HashMap<String, ShortcodeDefinition>,
}

接下来就是对site的实现,包括了页面生成器核心的功能,例如render_page核心的渲染页面流程。

pub fn render_page(&self, page: &Page) -> Result<()> {
    //首先检查页面的 meta 数据中是否允许渲染,如果不允许则直接返回
    if !page.meta.render {
        return Ok(());
    }

    //使用 Tera 模板引擎渲染页面 HTML
    let output = page.render_html(&self.tera, &self.config, &self.library.read().unwrap())?;
    //注入 livereload 脚本
    let content = self.inject_livereload(output);
    //将页面路径分割成组件数组,用于构建输出路径
    let components: Vec<&str> = page.path.split('/').collect();
    //将渲染后的内容写入到对应的 index.html 文件中
    let current_path = self.write_content(&components, "index.html", content)?;

    // 将页面相关的资源文件(如图片等)复制到输出目录中
    self.copy_assets(page.file.path.parent().unwrap(), &page.assets, &current_path)?;

    Ok(())
}

渲染完成之后就可以执行add_page函数,向站点添加新的页面。

再例如add_section向站点添加新的分区

pub fn add_section(&mut self, mut section: Section, render_md: bool) -> Result<()> {
    // 将分区的相对路径和永久链接添加到站点的 permalinks 映射中,这些链接信息后续会用于处理内部链接和生成 URL
    self.permalinks.insert(section.file.relative.clone(), section.permalink.clone());
    if render_md {
        section.render_markdown(
            &self.permalinks,
            &self.tera,//使用 Tera 模板引擎渲染分区的 Markdown 内容
            &self.config,//应用站点配置中的 Markdown 相关设置
            &self.shortcode_definitions,//处理分区中的短代码
        )?;
    }
    let mut library = self.library.write().expect("Get lock for add_section");
    library.sections.remove(&section.file.path);
    library.insert_section(section);

    Ok(())
}

其他核心功能函数包括set_base_url设置url,load导入所有的md文件并生成分区,render_xxx渲染生成各种通用文件,build构建功能(很多render_xxx函数都在build中被执行),等等。

rust小结

zola作为笔者第一次实际意义上接触的rust项目,既是为了搭建一个简单高效的静态博客网站,更是为了学习rust(当然最开始的目标就是和rust混个脸熟😅)

很好!

加油!

流水账

其实有时候还是有用的🤪

zola demo

  1. 安装zola
  2. zola init myblogdemo
  3. 选择一个现成的主题下载到myblogdemo/themes下
  4. 将主题文件夹内的config.toml文件中的内容,按需设置到根目录下的config.toml中,并将url等参数设置好
  5. zola serve运行

添加评论系统giscus

评论系统使用github的giscus,又恰巧我使用的主题apollo中留出了giscus接口,因此我只需要在giscus上设置好我的评论仓库然后将代码导入到_giscus_script.html中就可以。

重点是需要在每个博客md中设置评论使能:

+++
...
[extra]
version = "1.0.1"
comment = true
+++

云服务器部署

  1. 部署Nginx
  2. 设置域名
  3. 强制https
  4. 设置不缓存

问题记录

阿里云部署后无法渲染

config.toml要设置好,另外nginx的配置文件要设置正确。

页面更新后浏览器依然不刷新

  1. 设置nginx
# HTML 文件,禁用缓存
location ~* \.html$ {
    add_header Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate";
    add_header Pragma "no-cache";
    add_header Expires 0;
    try_files $uri $uri/ /index.html;
}

# 静态资源(JS、CSS、图片等),使用版本控制(如 ?v=1.0.0)
location ~* \.(css|js|jpg|jpeg|png|gif|svg|woff|woff2|ttf|eot)$ {
    expires 1y;
    add_header Cache-Control "public, must-revalidate, proxy-revalidate";
    try_files $uri $uri/ /index.html;
}
  1. 添加版本号
+++
...
[extra]
version = "1.0.1"
+++

Copyright 2025 wakamda 冀ICP备2025102883号-1