我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

Jekyll 3.x 升级到 4.x 完整指南:渲染引擎变更、配置语义与插件兼容性

Jekyll 3.x 升级到 4.x 完整指南:渲染引擎变更、配置语义与插件兼容性 Jekyll 3.x 升级到 4.x 完整指南渲染引擎变更、配置语义与插件兼容性【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyllJekyll 4.0 是 Jekyll 自 2015 年发布 3.0 以来的又一次主版本换代核心变化集中在模板渲染管线重构、Markdown 处理器升级、默认排除规则语义调整以及一批长期废弃配置项的最终移除。本文以官方升级文档 docs/_docs/upgrading/3-to-4.md 为主线结合当前仓库源码逐一拆解这些破坏性变更帮助你准确评估升级成本、修正模板与配置、并为插件作者提供源码级的适配指引最终平稳完成从 3.x 到 4.x 的迁移。升级前的环境准备Ruby 版本与 Jekyll 本体Jekyll 4 对运行环境提出了明确的最低要求Ruby 2.7.0当前仓库 jekyll.gemspec 中required_ruby_version 2.7.0与此一致。官方升级文档要求你先在终端确认本机 Ruby 版本ruby -v # 期望输出形如 ruby 3.4.1 (2024-12-25 revision 48d4efcb85)仓库文档数据 docs/_data/ruby.yml 中定义的最低版本为min_version: 2.7.0官方文档会随站点数据自动渲染该值请以ruby -v的实际输出为准。如果版本满足要求即可升级 Jekyll 本体gem update jekyll若项目使用 Bundler 管理依赖这是 Jekyll 站点最常见的实践建议改在项目根目录执行bundle update jekyll以便同步更新Gemfile.lock中 Jekyll 及其所有依赖的版本。post_url标签内置relative_url别再手动拼baseurl这是 3.x 升级到 4.x 最容易被忽略、却最容易造成链接重复的行为变更。在 Jekyll 4 中post_url标签在内部直接调用了relative_url过滤器因此会自动把站点的baseurl前缀到文章的url上。也就是说你在模板里不再需要、也不应该再手动拼接{{ site.baseurl }}。官方文档给出的迁移方式非常明确把{{ site.baseurl }}/{% post_url 2018-03-20-hello-world.markdown %}改为{% post_url 2018-03-20-hello-world.markdown %}如果站点本身没有配置baseurl两种写法输出的 URL 恰好一致问题会被悄悄掩盖但只要_config.yml中设置了baseurl例如部署到 GitHub Pages 子路径或自建站点的子目录旧写法就会生成baseurl/baseurl/文章路径这种重复前缀的坏链接。从源码看这一行为由 lib/jekyll/tags/post_url.rb 落实PostUrl标签类通过include Jekyll::Filters::URLFilters引入了 URL 过滤器模块并在命中目标文章后直接return relative_url(post)。而relative_url的真正实现位于 lib/jekyll/filters/url_filters.rb它读取站点配置中的baseurl经sanitized_baseurl去掉尾部斜杠并与输入 URL 拼接。你可以用grep -rn post_url test/查看测试用例确认该标签在不同baseurl场景下的输出。排查建议升级后全局搜索site.baseurl.*post_url或{% post_url前带/前缀的写法将二者拆开。模板渲染管线重构解析一次、缓存、多次渲染Jekyll 4 对模板的处理方式做了根本性调整目的是缩短整体构建时间同一个模板文件只解析parse一次解析结果被缓存在内存中随后按需渲染多次不同页面/文档共享同一份解析结果仅传入各自的payload。这一以空间换时间的设计可以从渲染器源码直接看到。核心缓存位于 lib/jekyll/liquid_renderer.rb# A persistent cache to store and retrieve parsed templates based on the filename # via LiquidRenderer::File#parse # # It is emptied when self.reset is called. def cache cache || {} end而 lib/jekyll/liquid_renderer/file.rb 的parse方法正是文档中提到的关键入口def parse(content) measure_time do renderer.cache[filename] || Liquid::Template.parse(content, :line_numbers true) end template renderer.cache[filename] self end注意||同一个path文件名第二次调用parse时会直接返回缓存中的同一个Liquid::Template实例而不会重新解析。另外每次render之前都会调用reset_template_assigns清空template.instance_assigns见 lib/jekyll/liquid_renderer/file.rb避免不同渲染之间互相污染。对普通站点作者这一改动通常是透明的构建速度反而更快无需任何操作。对插件作者如果插件依赖如下写法template site.liquid_renderer.file(path).parse(content)请务必注意对给定的path该行返回的template一个Liquid::Template实例始终是同一个对象。渲染仍然照常进行payload也会按原样传入但你不能把payload记忆化memoize或缓存在插件实例中——否则后续渲染会拿到上一次的陈旧数据。如果插件确实需要每次拿到不同的template可以绕过 Jekyll 的缓存层直接调用 Liquid 本身# 变更前走 Jekyll 缓存同一 path 返回同一对象 template site.liquid_renderer.file(path).parse(content) # 变更后直接调用 Liquid每次都是新模板 template Liquid::Template.parse(content)未开启输出output的集合不再产出静态文件Jekyll 3.x 中非posts集合可以同时存放 Markdown 文档和静态资源但行为存在不一致。到了 Jekyll 4规则被收紧并明确只要集合没有配置output: true那么该集合里的文档documents和静态资源static assets都不会被输出到目标目录_site。从 lib/jekyll/collection.rb 可以看到判断依据# files in the output. # # Returns true if the write metadata is true, false otherwise. def write? !!metadata.fetch(output, false) end也就是说集合是否写入输出目录完全由元数据output决定默认是false。而集合的读取过程lib/jekyll/collection.rb会区分带 YAML 头的文件读为文档与不带 YAML 头的文件读为静态文件StaticFile并统一site.static_files.concat(files)挂到站点静态文件列表中——但这些静态文件最终能否落盘仍受集合output开关约束。如果你的某个集合只用于组织数据、不希望生成页面请确认其配置保持collections: glossary: output: false # 仅组织数据不输出若需要集合里的资源如图片、CSS被复制到_site则必须显式开启collections: gallery: output: true # 文档与静态资源都会被输出排除exclude与包含include语义变化Jekyll 4 对默认排除数组做了增强并且改变了合并语义用户的exclude配置不再覆盖默认值而是追加到默认排除数组之上若条目已存在则去重。官方文档给出的默认排除清单如下# default excludes exclude: - .sass-cache/ - .jekyll-cache/ - gemfiles/ - Gemfile - Gemfile.lock - node_modules/ - vendor/bundle/ - vendor/cache/ - vendor/gems/ - vendor/ruby/对照当前仓库 lib/jekyll/configuration.rbDEFAULT_EXCLUDES常量在文档基础上还追加了.ruby-lsp编辑器语言服务器目录合并逻辑由add_default_excludes实现def add_default_excludes config clone return config if config[exclude].nil? config[exclude].concat(DEFAULT_EXCLUDES).uniq! config end它是在Configuration.from构建配置时被调用的lib/jekyll/configuration.rb。对应的回归测试在 test/test_configuration.rb逐一断言node_modules、Gemfile、Gemfile.lock、gemfiles、vendor/*以及.jekyll-cache、.sass-cache、.ruby-lsp始终出现在排除列表中。如何强制处理被排除的目录/文件使用include数组它优先于排除规则。官方示例# 覆盖被排除的条目配置以及默认的 include 数组[.htaccess] include: - .htaccess - node_modules/uglifier/index.js上面配置的效果是node_modules整体仍被默认排除但其中的node_modules/uglifier/index.js会被单独纳入处理node_modules里其余文件一律忽略。注意include与exclude的语义并不对称——默认include数组[.htaccess]仍然会被用户配置整体覆盖所以如果你需要.htaccess出现在生成站点中必须像示例一样显式把它写进include列表。另外include与exclude的值必须是数组。若配置成字符串例如exclude: README.md, Gemfilevalidate阶段会抛出InvalidConfigurationError见 lib/jekyll/configuration.rb测试 test/test_configuration.rb 覆盖了这类错误场景。Markdown 处理器升级到 Kramdown v2Jekyll 4 彻底放弃了对kramdown-1.x的支持全面切换到 Kramdown 2.x。当前仓库 jekyll.gemspec 的运行时依赖可以佐证s.add_runtime_dependency(kramdown, ~ 2.3, 2.3.1) s.add_runtime_dependency(kramdown-parser-gfm, ~ 1.0)Kramdown 2.x 的关键变化是核心功能之外的能力被拆分成了独立扩展 gem需要按需额外安装。在 Jekyll 4.0 中kramdown-parser-gfmGitHub Flavored Markdown 解析器会随 Jekyll 自动安装其余扩展则需要用户根据自身需求在Gemfile中手动声明例如gem kramdown-math-katex # 数学公式渲染 gem kramdown-converter-pdf # PDF 转换官方文档特别提醒两点kramdown-converter-pdf会被 Jekyll 核心忽略。要让 Jekyll 把 Markdown 转成 PDF必须依赖一个继承Jekyll::Converter、并实现所需方法的插件方法要求见 插件转换器文档。官方给出的参考实现module Jekyll External.require_with_graceful_fail kramdown-converter-pdf class Markdown2PDF Converter safe true priority :low def matches(ext) # match only files that have an extension exactly .markdown ext ~ /^\.markdown$/ end def convert(content) Kramdown::Document.new(content).to_pdf end def output_ext .pdf end end end这里用到的External.require_with_graceful_fail定义于 lib/jekyll/external.rb其作用是尝试加载 gem若缺失则优雅降级并给出提示而非直接崩溃。提供版本化 Jekyll 环境的厂商如 Docker 镜像、GitHub Pages 等需要在其发行版中手动白名单kramdown 的扩展 gem否则这些扩展在 Jekyll 4.0 环境中将不可用。废弃配置选项的最终移除Jekyll 4.0 移除了在 3.x 系列中历经多个版本被标记为废弃deprecated的全部旧配置项。与旧版遇到废弃键输出警告并静默映射到新键的温和做法不同4.0 起不再输出任何废弃警告也不再把旧键的值优雅赋给新键。具体行为取决于配置项键已完全无效直接忽略键仍然有效、但关联的值类型不正确抛出InvalidConfigurationError。例如exclude、include若被配置为非数组会走 lib/jekyll/configuration.rb 的check_include_exclude校验并抛错plugins若被配置为字符串而非 gem 名数组则由check_plugins抛错lib/jekyll/configuration.rb。这提示升级时务必清理_config.yml中的历史遗留键例如 2.x 时代的relative_permalinks、gems等 3.x 已废弃项避免静默失效造成的配置误解。升级自检清单完成 Jekyll 4 升级后建议按以下顺序逐一核对环境ruby -v确认 Ruby 2.7.0再执行gem update jekyll或bundle update jekyll模板全局搜索并修正所有{{ site.baseurl }}/{% post_url ... %}写法改为{% post_url ... %}集合检查每个集合的output配置确认需要输出的集合已设置output: true排除/包含确认exclude中无需与默认值较劲的条目——它们现在只会被追加合并需要放行的文件改用include列出并记得把.htaccess重新加回Markdown核对Gemfile中 kramdown 相关扩展是否齐全kramdown-parser-gfm已随 Jekyll 安装使用kramdown-converter-pdf的站点需改为自写Jekyll::Converter子类插件配置清理所有 3.x 时代遗留的废弃键确认exclude、include、plugins等均为数组类型避免升级后触发InvalidConfigurationError插件若自研插件依赖site.liquid_renderer.file(path).parse(content)确认没有对template或payload做跨渲染的记忆化必要时改用Liquid::Template.parse(content)绕过缓存。升级涉及的核心实现均可在本仓库相应源码与测试中找到依据渲染缓存见 lib/jekyll/liquid_renderer/file.rb 与 lib/jekyll/liquid_renderer.rbpost_url行为见 lib/jekyll/tags/post_url.rb排除语义见 lib/jekyll/configuration.rb 与 test/test_configuration.rb集合输出规则见 lib/jekyll/collection.rb。按上述清单逐项处理即可顺利完成 Jekyll 3.x 到 4.x 的迁移。【免费下载链接】jekyll:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby项目地址: https://gitcode.com/gh_mirrors/je/jekyll创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表