August 16, 2021

如何创建可视化的Web Bookmark

#Vue.js #Vite #Chrome #Extension

最近看到 GitHub Blog 的一篇文章,《一个用于创建 Open Graph 图像的框架》,文中介绍了 GitHub 开发者是如何提高网站的 SEO 的,通过借助 Open Graph Protocol,优化站点创建了一系列利于社交网站爬虫抓取的元数据信息,其中包含了即时生成的站点信息图片,将以往“大头贴”式的站点图片改善为更具可视化意义的站点图片。

感兴趣可以先了解下原文:A framework for building Open Graph images

引起我的关注的是 Twitter 是如何做到根据链接获取 Twitter Card 的,其实答案作者也提到了。用到的技术是 Open Graph Protocol 。那么简单介绍一下它。

# 什么是 Open Graph Protocol?

Open Graph Protocol,简称 OG 协议,它是由 Facebook 在2010年首次被提出的一种网页元信息标记协议,是一种为社交分享而生的协议。

目前主流的社交媒体网站都已支持了 OG 协议。比如 Twitter、LinkedIn、Pinterest、GitHub,但是 Twitter 也有自家的 Twitter Cards 协议。当然 Twitter 也支持 OG 协议的。

看个例子🌰:

我们打开一个 GitHub 网址,比如:https://github.com/vuejs/vue-next

202108_twitter-og-protocol

通过 Chrome Devtools 可以看到 HTML 文档 header 中有一些 meta 标签声明:

  • 蓝色框内是 twitter cards 协议的
  • 粉色框内是 OG 协议的

这些 meta 标签声明就是为了便于其他站点的爬虫抓取有效信息用的。

# Twitter Card

Twitter 在发表推文或者在分享内容时,支持输入一个🔗链接,即可生成一个 Twitter Card

202108_twitter-car

这个卡片中包含了一些信息:

  • twitter:image:src - 图片地址
  • twitter:title - 站点标题
  • twitter:description - 描述信息
  • twitter:site - 站点信息
  • twitter:card - 卡片描述

现在很容易想到,卡片的生成就是通过 twitter cards 协议声明抓取的站点 meta 标签信息,如果站点没有声明 twitter cards 协议,那么就抓取 OG 协议的 meta 标签信息进行展示。

# Notion Web Bookmark

类似的,Notion 也提供另一个可以创建类 Twitter Card 的功能,称之为 Web Bookmark。输入一个链接,展示为一个 Bookmark

只不过看上去排版不太一样,但仍然包含了一些信息:图片、标题、描述、Icon

202108_notion-bookmark

简单看了下,Notion 是通过接口实现的 Web Bookmark 功能

# 实现一个 Twitter Card / Notion Web Bookmark

如果想实现一个像 Twitter 或者 Notion 一样,输入一个链接即可生成卡片的功能,看上去还比较好实现,需要爬取网站的 meta 标签信息,进行展示即可。其实我更倾向于 Notion 对标签信息的定义,Twitter Card 有些过于强调为自家实现的功能,Web Bookmark 这个名字就更通用。那么下面我将构建一个 Web Bookmark

用到的技术栈

  • vercel serverless functions
  • metascraper
  • chrome extensions
  • vite
  • vitesse-modernized-chrome-ext

# Web Bookmark 的服务端实现

# 开发一个 Serverless Functions 接口

# 基于 Vercel 的 Serverless Functions

我基于 Vercel 搭建了一个 serverless functions 服务: https://metafy.vercel.app

这个服务可以说是一个后端接口,可以使用 Node.js 来编写,并且返回一个 JSON 结构的 API。

只要在项目的根目录下放置一个 api 文件夹,支持 .js 以及 .ts 的文件

例如 api/index.js

// api/index.js
module.exports = (req, res) => {
  const { name = 'World' } = req.query;
  res.status(200).send(`Hello ${name}!`);
};
1
2
3
4
5

通过 vercel 部署服务后,得到一个域名,比如

https://node-api.now-examples.vercel.app/

这时候就可以通过在链接后加入 api 路径以及查询条件,即可返回新的内容。

https://node-api.now-examples.vercel.app/api/hello?name=reader

# 编写获取站点信息的接口

主要用到的是 metascraper 这个库,metascraper 可以从站点抓取 OG 协议的 meta 信息,可以按需引用想获取的信息插件,使用起来比较方便。

比如官方的例子:

const metascraper = require('metascraper')([
  require('metascraper-author')(),
  require('metascraper-date')(),
  require('metascraper-description')(),
  require('metascraper-image')(),
  require('metascraper-logo')(),
  require('metascraper-clearbit')(),
  require('metascraper-publisher')(),
  require('metascraper-title')(),
  require('metascraper-url')()
])

const got = require('got')

const targetUrl = 'http://www.bloomberg.com/news/articles/2016-05-24/as-zenefits-stumbles-gusto-goes-head-on-by-selling-insurance'

;(async () => {
  const { body: html, url } = await got(targetUrl)
  const metadata = await metascraper({ html, url })
  console.log(metadata)
})()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

输出的内容如下:

{
  "author": "Ellen Huet",
  "date": "2016-05-24T18:00:03.894Z",
  "description": "The HR startups go to war.",
  "image": "https://assets.bwbx.io/images/users/iqjWHBFdfxIU/ioh_yWEn8gHo/v1/-1x-1.jpg",
  "publisher": "Bloomberg.com",
  "title": "As Zenefits Stumbles, Gusto Goes Head-On by Selling Insurance",
  "url": "http://www.bloomberg.com/news/articles/2016-05-24/as-zenefits-stumbles-gusto-goes-head-on-by-selling-insurance"
}
1
2
3
4
5
6
7
8
9

Vercel Serverless Functions + metascraper = metafy

整合起来我写一个可以获取站点信息的 Serverless Functions

源码地址:https://github.com/xiaoluoboding/metafy

一个例子:https://metafy.vercel.app/api?url=https://github.com/xiaoluoboding/metafy

# Web Bookmark 的前端实现

# 需求定位

API 接口搭建完毕,那么开发一个 Web Bookmark 吧,考虑到输入一个链接得到一个 Web Bookmark 的需求,怎样更容易获取链接呢,我的想法是借助浏览器插件的能力,获取浏览器当前 Tab 页的链接进而展示 Web Bookmark,那么我的目标是构建一个浏览器插件。

# vitesse-webext

正好最近也在开发基于 Chrome 浏览器的插件,给大家推荐一个我认为目前搭建浏览器插件最快的方式,并且开发体验相当爽,由 antfu 创建的一个浏览器插件开发模版 vitesse-webext

vitesse-webext 是一个很棒的开发模版,基于 Vite 搭建,无需刷新即可享受热更新带来的开发体验提升,集成了 Vue 3、Windi CSS 和一些好用的 Vite 插件,当然使用的是 TypeScript 进行开发。

# vitesse-modernized-chrome-ext

然而我没有使用 vitesse-webext,原因是它是基于 Chrome Extension Manifest V2 版本进行的通用声明,还需兼容 Firefox 浏览器,而我想基于 Chrome Extension Manifest V3 版本进行开发。所以我基于它派生了一个只适用于 Chrome Extension Manifest V3 的模版,vitesse-modernized-chrome-ext

我同时扩展了模版的能力,支持了暗色模式以及多语言功能,当然也是基于 vitesse 来做的,感谢 antfu 提供的好用的工具。

# chrome-web-bookmark

啰嗦了半天,最后我使用我创建的模版 vitesse-modernized-chrome-ext 创建了 chrome-web-bookmark ,功能很简单,点击插件 Icon 时,弹出一个 Popup ,获取当前页面的 URL,进而来展示当前页面的 Web Bookmark。

就像这个样子:

202108_chrome-web-bookmark

# 使用方式

1、克隆仓库 & 安装依赖

git clone https://github.com/xiaoluoboding/vitesse-modernized-chrome-ext.git

cd chrome-web-bookmark

yarn
# or
pnpm i
1
2
3
4
5
6
7

2、构建生产目标

yarn build
# or
pnpm build
1
2
3

3、加载本地插件

选择 chrome-web-bookmark/extension 目录,即可加载插件

源码地址:https://github.com/xiaoluoboding/chrome-web-bookmark

# 扩展

在网罗解决方案的时候发现了这些站点,他们提供相应的服务以此盈利,是个不错的IDEA

# 参考