11ty:如何自动生成Twitter标题卡

526 阅读5分钟

对于这个博客的重新设计,我创建了自动生成的Twitter标题卡。因此,每当人们在社交媒体上分享我的东西时,他们会收到一张漂亮的卡片,告诉他们文章的标题和发布日期。

而人们应该在社交媒体上分享这些文章,不是吗?

A tweet by @TypeScriptDaily showing one of my articles

我使用Eleventy作为这个网页的静态网站生成器,感谢他们的分页功能,为每篇文章创建Twitter卡片只需要很少的投资。

Eleventy的分页功能#

Eleventy的一个重要功能是集合。Eleventy试图从你的源文件中收集所有可解析的文件到一个大的集合中,你有可能将这一大堆的数据集中到不同的组。其中一个是帖子,这适用于我所有的博客文章。

在很多情况下,你想把你的集合作为一个整体或在几个页面上浏览。Eleventy的分页功能正是让你做到这一点。它获取一组数据,并根据页面大小将其切分。这可以在前面的内容中定义。

---
pagination:
  data: collections.posts
  size: 10
  alias: pagedPosts
---

在上面的例子中,我从帖子集合中创建了每个有10个项目的页面,将信息存储在一个名为pagedPosts 的数组中。我们在这个数组上循环,在模板中显示内容。有效地创建了一个分页概览。

分页来重新映射你的集合#

那么,我们如何为我们的预告使用分页呢?诀窍在于分页的大小。如果我们把分页大小设置为1会发生什么?我们为帖子集合中的每个条目得到一个页面。这样,我们就把博客的全部内容重新映射到一个新的输出中。

这可以是另一个HTML或XML页面,或JSON,或在我们的例子中。一个SVG。

---
pagination:
  data: collections.posts
  size: 1
  alias: post
permalink: /teasers/{{ pagination.items[0].permalink | slug  }}.svg
eleventyExcludeFromCollections: true
---

上面的代码

  1. 将分页大小设置为1,有效地为每篇文章创建另一个页面
  2. 将帖子存储在变量post ,这样我们就可以在模板中访问它。
  3. 将其内容重新映射到一个新的输出URL。一个原始帖子的固定链接,但有一个svg结尾。注意:我只是通过自己设置每个固定链接来做到这一点。这可以进一步自动化。
  4. 通过eleventyExcludeFromCollections: true ,我确保新创建的页面会被添加到整个集合列表中。

这就是基本的设置。现在来看看模板的内容

创建一个SVG#

我为这个网站所做的是用Sketch创建一个SVG。一个简单的,只有一点文字的。我尝试了系统字体,因为一旦我在SVG或PNG中渲染这个,我不确定我有哪些字体可用。我使用了一些基于真实博客文章的假文本,然后复制了模板中的SVG代码。

---
pagination:
  data: collections.posts
  size: 1
  alias: post
permalink: /teasers/{{ pagination.items[0].permalink | slug  }}.svg
eleventyExcludeFromCollections: true
---
<?xml version="1.0" encoding="UTF-8"?>
<svg width="1452px" 
  height="843px" viewBox="0 0 1452 843"
  version="1.1" xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink">
  <!-- here come the contents -->
</svg>

我搜索了一下为什么要设置文字的部分,并删除了所有现有的行。我把它改成了一个循环,在这个循环中,我把文章的标题拆开,这样每一行都有合适的字符数。

<text id="text"
  fill="url(#linearGradient-3)"
  font-family="Arial, Helvetica, sans-serif"
  font-size="100" font-weight="bold" line-spacing="101">
  {% for line in post.data.title | splitlines %}
  <tspan x="81" y="{{247 + loop.index0 * 141}}">{{line}}</tspan>
  {% endfor %}
</text>

根据我设置的字体大小,我将y坐标设置为一个偏移量(在这种情况下是247),加上当前行的索引和一个带行高的字体大小(141)。

splitlines 是我在我的 配置文件中创建的一个过滤器。.eleventy.js

config.addFilter('splitlines', function(input) {
  const parts = input.split(' ') /* 1 */
  /* 2 */
  const lines = parts.reduce(function(prev, current) {
    /* 3 */
    if(!prev.length) {
      return [current]
    }
    
    /* 4 */
    let lastOne = prev[prev.length - 1]
    if(lastOne.length + current.length > 18) {
      return [...prev, current]
    }
    prev[prev.length - 1] = lastOne + ' ' + current
    return prev
  }, [])
  return lines
})

我是这样做的。

  1. 我将标题按每个词拆开
  2. 遍历所有单词
  3. 如果数组是空的,我就用第一个词创建一个数组
  4. 对于每一个后续的单词,我都会检查单词的串联是否超过了我设想的每一行的字符数(本例中为18)。
    1. 如果是空的,我就把新词添加到下一行
    2. 否则,我在一行中串联单词

我也对帖子的日期做了一些类似的处理。

这就为我正在写的每篇博文提供了一个SVG。

创建一个PNG#

最后一件事是为每个SVG创建一个PNG。我还没能通过Eleventy做到这一点。所以我求助于Gulp。这其实是故意的,因为我想通过最大限度的并行化来节省时间。

这是我的Gulpfile.js 。我只需要一个插件。

const gulp = require('gulp');
const svg2png = require('gulp-svg2png');

gulp.task('default', function() {
  return gulp
    .src('./dist/teasers/*.svg')
    .pipe(svg2png())
    .pipe(gulp.dest('./dist/teasers/'));
})

请注意,这是很重的资源。取决于你的网站有多大,你可能想逐步进行,或者把结果储存在某个地方,而不是每次构建运行都创建这个。

至于这个网站。Eleventy在不到2秒的时间内完成了HTML+SVG的构建。在Vercel上转换PNG还需要20秒。这仍然比一个 "Hello world "风格的Gatsby网站快。所以我认为每次都这样做是合理的 😉

设置元标签#

最后,但不是最不重要的,我在每篇博客文章的元信息中添加了结果。

{% set imgPath = permalink | slug %}

<meta property="og:image" 
  content="https://fettblog.eu/teasers/{{ imgPath }}.png">
<meta property="og:image:secure_url"
  content="https://fettblog.eu/teasers/{{ imgPath }}.png">
<meta name="twitter:image"
  content="https://fettblog.eu/teasers/{{ imgPath }}.png">