- 前端
- CMS
【免费下载链接】jekyll
:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby
在 Jekyll 中,post.excerpt默认截取文章正文的第一个段落作为摘要,但当正文段落中的引用式链接(reference-style link)定义位于分隔符之后的文末时,摘要中的链接会失效。本指南以仓库中专门用于回归测试的文档 test/source/_posts/2016-08-16-indented-link-references.markdown 为切入点,结合 lib/jekyll/excerpt.rb 的实现与 test/test_excerpt.rb 的用例,完整讲解 Jekyll 摘录提取链接引用定义的规则:支持哪些缩进形式、如何识别并忽略代码块中的伪链接定义,以及如何在自己的站点中规避摘要链接失效问题。
一、为什么摘录需要链接引用定义
Jekyll 的摘录机制默认按excerpt_separator(默认值为"\n\n",即空行,见 lib/jekyll/configuration.rb)把文档内容一分为二:分隔符之前的部分是"头部"(head),之后是"尾部"(tail)。摘录默认取头部内容,这相当于 Markdown 正文的第一个段落。
问题在于:Markdown 的引用式链接(如[link][link_0])允许把链接地址以"定义"的形式写在文档任何位置,通常习惯放在文末。如果一个段落的链接定义被放在分隔符之后(即尾部),那么仅截取头部作为摘录时,链接定义就丢了——摘录渲染出来后[link]会退化成纯文本,而不是可点击的链接。
为此,Jekyll 在提取摘录时会主动扫描尾部,把"正文中确实使用到"的链接引用定义追加到摘录末尾,从而保证摘录内部的引用式链接仍然有效。本文档对应的 lib/jekyll/excerpt.rb 注释也明确说明了这一点:"all markdown-style link references will be appended to the excerpt"(所有 Markdown 风格的链接引用都会被追加到摘录中)。
二、回归测试文档逐行解读
仓库中的 test/source/_posts/2016-08-16-indented-link-references.markdown 是一份专门构造的测试夹具(fixture),全文件仅 16 行,用于验证"缩进的链接引用定义"这一边界场景:
--- --- This is the first paragraph. It [has][link_0] [lots][link_1] [of][link_2] [links][link_3]. This is the second paragraph. It has sample code that should not be extracted: [fakelink]: www.invalid.com And here are the real links: [link_0]: www.example.com/0 [link_1]: www.example.com/1 [link_2]: www.example.com/2 [link_3]: www.example.com/3文件包含三类关键要素:
- 头部引用:第一个段落通过
[link_0]到[link_3]四个引用式链接引用了四个目标,这是摘录正文的组成部分; - 代码块陷阱:第二个段落里有一个以 4 个空格缩进的
[fakelink]: www.invalid.com,按 Markdown 语法,4 空格缩进行属于代码块,不应该被当作链接定义提取出来; - 真实定义区:文末按 0、1、2、3 个空格逐级递增缩进排列了四个真实链接定义
[link_0]~[link_3],用来验证 Jekyll 对"缩进不超过 3 个空格的链接定义"的支持。
注意前文还有一个细节:四个链接定义并非全部顶格书写,[link_1]缩进了 1 个空格、[link_2]缩进了 2 个空格、[link_3]缩进了 3 个空格。这正是本测试的核心命题——到底允许链接定义缩进几个空格。
三、源码实现:0 到 3 个空格是关键边界
摘录提取的核心逻辑位于 lib/jekyll/excerpt.rb:
LIQUID_TAG_REGEX = %r!{%-?\s*(\w+)\s*.*?-?%}!m.freeze MKDWN_LINK_REF_REGEX = %r!^ {0,3}(?:(\[[^\]]+\])(:.+))$!.freeze def extract_excerpt(doc_content) head, _, tail = doc_content.to_s.partition(doc.excerpt_separator) return head if tail.empty? head = sanctify_liquid_tags(head) if head.include?("{%") definitions = extract_markdown_link_reference_definitions(head, tail) return head if definitions.empty? head << "\n\n" << definitions.join("\n") end def extract_markdown_link_reference_definitions(head, tail) [].tap do |definitions| tail.scan(MKDWN_LINK_REF_REGEX).each do |segments| definitions << segments.join if head.include?(segments[0]) end end end整个流程可以拆解为三步:
第一步:按分隔符切分。doc_content.partition(doc.excerpt_separator)把文档切成 head(摘录正文)和 tail(其余部分)。如果分隔符之后没有内容(tail.empty?),直接返回 head,不做任何链接提取。
第二步:用正则扫描尾部链接定义。关键正则MKDWN_LINK_REF_REGEX逐行匹配tail中满足以下条件的行:
^ {0,3}:行首只允许0 到 3 个空格。这是与 Markdown 规范对齐的边界——缩进 4 个空格及以上的行会被解析为代码块(indented code block),不是普通的链接定义行,因此被正则主动排除;(\[[^\]]+\]):捕获链接标签,形如[link_0];(:.+):捕获从冒号开始的整段定义内容,形如: www.example.com/0。
第三步:按需追加。extract_markdown_link_reference_definitions使用head.include?(segments[0])做二次过滤:只有链接标签确实出现在摘录正文 head 中的定义才会被追加进摘录。这一"按需提取"的设计对应 docs/_docs/history.md 中记录的 "Add support for indented link references on excerpt (#5212)" 以及 "Push Markdown link refs to excerpt only as required (#7577)" 等演进,避免了把整篇文档所有链接定义都塞进摘录造成冗余。
针对本测试文件执行上述流程,结果应当是:四个缩进 0~3 空格且被正文引用的[link_0]~[link_3]定义被提取追加,而缩进 4 空格的[fakelink]因为超出行首空格上限,被当作代码块内容忽略。
四、测试用例:三个断言验证三条规则
配套测试位于 test/test_excerpt.rb,在context "with indented link references"分组下用同一个 fixture 文档验证了三个行为:
context "with indented link references" do setup do @post = setup_post("2016-08-16-indented-link-references.markdown") @excerpt = @post.excerpt end should "contain all refs at the bottom of the page" do 4.times do |i| assert_match "[link_#{i}]: www.example.com/#{i}", @excerpt.content end end should "ignore indented code" do refute_match "[fakelink]:", @excerpt.content end should "render links properly" do @rendered_post = @post.dup do_render(@rendered_post) output = @rendered_post.data["excerpt"].output 4.times do |i| assert_includes output, "<a href=\"www.example.com/#{i}\">" end end end- "contain all refs at the bottom of the page":断言摘录
content中包含全部 4 条真实链接定义,验证 0~3 空格缩进的定义均被正确提取并追加到摘录末尾; - "ignore indented code":断言摘录
content中不包含[fakelink],验证 4 空格缩进的代码块行未被误判为链接定义——这是防止摘录内容被"污染"的关键保护; - "render links properly":对摘录执行真实渲染(
do_render通过Jekyll::Renderer走完整渲染管线),断言输出 HTML 中出现<a href="www.example.com/#{i}">,从端到端确认追加的定义能让摘录里的引用式链接被正确渲染成<a>标签。
测试中setup_post通过 test/test_excerpt.rb 构造Jekyll::Document并从_posts集合读取文档,do_render则显式注入simple.html布局后执行渲染,整个过程与真实站点构建路径一致。
五、结合 Markdown 规范理解边界设计
Jekyll 将"行首 4 空格"设为提取边界并非随意为之,而是与 CommonMark / 经典 Markdown 规范保持一致:
- 缩进 0~3 空格:属于普通段落文本行,符合链接引用定义的合法写法,因此被
^ {0,3}接纳; - 缩进 4 空格及以上:在 Markdown 中被解析为缩进代码块,其中的
[fakelink]: ...只是代码示例,不是链接定义,提取它既没有意义,还会把无关文本混入摘录。
这一点也让测试夹具的设计更完整:文档故意在"第二个段落"里放置缩进代码示例,并让它出现在分隔符之后的 tail 区,专门用来证明正则的代码块豁免能力——若没有{0,3}上限,[fakelink]会被误追加进摘录,测试 2("ignore indented code")就会失败。
六、实践指南:在自己的站点中规避摘要链接失效
理解了上述机制后,可以总结出几条可落地的写作规范:
- 链接定义可以放在正文后面:只要定义写在
excerpt_separator(默认空行)之后的任意位置,且对应标签在摘录正文中被引用,Jekyll 就会把定义自动追加进摘录,无需手工复制; - 允许适度缩进,但别超过 3 个空格:链接定义行首可以有 0~3 个空格缩进(例如为了视觉对齐),Jekyll 都能识别;一旦达到 4 个空格就会被当作代码块忽略,导致摘要中对应链接失效;
- 不要在分隔符之后用缩进代码展示"链接定义示例":如果尾部存在 4 空格缩进的伪定义(如本文档中的
[fakelink]),它会被安全忽略——但反过来也意味着,如果你希望某个链接定义生效,就绝不能以 4 空格缩进书写; - 自定义分隔符不影响链接提取:全局可在
_config.yml设置excerpt_separator,或在 Front Matter 中按文档单独覆盖(参见 docs/_docs/posts.md 的excerpt_separator: <!--more-->示例)。分隔符改变只会影响 head/tail 的切分点,链接定义的提取规则(正则与按需追加)保持不变,相关取值优先级见 lib/jekyll/document.rb; - 可用 Front Matter 中的
excerpt完全接管:如果自动提取不符合预期,直接在 Front Matter 里显式写excerpt字段即可覆盖自动生成的摘要,这是最直接的控制手段。
七、FAQ 与排查思路
Q:摘录里出现了我不想要的[xxx]: url文本?A:检查该定义是否被摘录正文真实引用。extract_markdown_link_reference_definitions只在head.include?(segments[0])时才追加,未在正文出现的定义不会被提取。
Q:摘录里的引用式链接渲染后没有变成<a>?A:优先检查对应定义行的行首缩进。将行首空格数压到 0~3 个(推荐顶格),避免 4 空格缩进触发代码块解析。
Q:整个文档较长时,链接定义提取会影响构建性能吗?A:从源码看提取只是对 tail 做一次正则scan,且只有被正文引用的定义才会被拼接进摘录字符串,属于轻量操作。
通过本文的源码拆解与测试验证可以确认:Jekyll 对缩进链接引用的提取遵循"0~3 空格合法、4 空格归代码块"的 Markdown 语义边界,并采用"仅提取正文实际引用的定义"的按需策略。掌握这一规则,你就能放心地在文章文末维护引用式链接,同时保证首页列表里的post.excerpt链接完整可用。
- 前端
- CMS
【免费下载链接】jekyll
:globe_with_meridians: Jekyll is a blog-aware static site generator in Ruby
相关推荐
Prettier 处理 Markdown 链接中的 HTML 字符引用:entity.md 测试用例深度解析
Prettier 处理 Markdown 链接中的 HTML 字符引用:entity.md 测试用例深度解析 本文围绕 Prettier 仓库中 tests/f
开发工具格式化CLIBiome Markdown 格式化器如何解析与格式化引用链接(Reference Links):从测试规格到源码实现
Biome Markdown 格式化器如何解析与格式化引用链接(Reference Links):从测试规格到源码实现 导读 引用链接(Reference Li
开发工具Lint格式化静态分析代码质量前端Jekyll Post Excerpt 提取机制深入解析:以带 Layout 的博文夹具为例
Jekyll Post Excerpt 提取机制深入解析:以带 Layout 的博文夹具为例 本文以 Jekyll 仓库测试夹具 test/source/_po
前端CMS
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考