惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
T
Threatpost
WordPress大学
WordPress大学
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
PCI Perspectives
PCI Perspectives
T
The Exploit Database - CXSecurity.com
Y
Y Combinator Blog
雷峰网
雷峰网
爱范儿
爱范儿
The Hacker News
The Hacker News
Last Week in AI
Last Week in AI
Simon Willison's Weblog
Simon Willison's Weblog
T
Tor Project blog
S
Securelist
宝玉的分享
宝玉的分享
L
LangChain Blog
O
OpenAI News
AI
AI
P
Privacy International News Feed
L
LINUX DO - 最新话题
D
DataBreaches.Net
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
M
MIT News - Artificial intelligence
Security Archives - TechRepublic
Security Archives - TechRepublic
月光博客
月光博客
博客园 - 【当耐特】
T
Tailwind CSS Blog
C
Cybersecurity and Infrastructure Security Agency CISA
H
Help Net Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Hacker News - Newest:
Hacker News - Newest: "LLM"
腾讯CDC
Jina AI
Jina AI
The Last Watchdog
The Last Watchdog
K
Kaspersky official blog
Webroot Blog
Webroot Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Blog — PlanetScale
Blog — PlanetScale
MyScale Blog
MyScale Blog
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
Recorded Future
Recorded Future
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 三生石上(FineUI控件)
The Cloudflare Blog

Surmon.me

一人有限集团 你就是不敢 创造力是温柔的谎言 人类正在退出人类 AI 代替不了这样的你 脉冲点火背后的架构设计 基于 Cloudflare 生态的 AI Agent 实现 NodePress 支持用户登录了 从统计学习到通用智能 2025 投资报告:走慢的路 无依之地 会杀人的菩萨 无我不是共识 文化的积重与偏见 当下即安 科学的尽头是态度 无我不是 Egoless 信仰不因恐惧而存在 世间无解的矛与盾 先别急着做些什么 佛不需要你的皈依 真理的幻觉 两扇大门 造心里的浮屠 自胜者强 逻辑与智慧 真的相 快乐的秘密 只需愿意 是名体验 最深沉的梦 森林里倒下的树 现象与相 庸人自扰 React 与 Vue 的完美融合 开心就好吗 与原生家庭和解 两支毒箭 怎么自净其意 一尘不染 一片白云 让风穿膛而过 喝下去,然后闭嘴 活在当下 当纠结发生时 唯「我」独尊 一场把戏(时间) 一场把戏(二元对立) “我” 和 “我” 谁是众生? 船里没有人 玫瑰不需要说话 没有人能渡任何人 你我为轮,使之不再 当我们在谈论独立时 自我约束就是最好的自我接纳 从善与恶的表象出发 佛法不是心理学 别人眼中的你并不是你 高高山上走 祝你心想事成 祝你的噩梦早日发生 道是无情却有情 裙子只为自己而穿 不要盲目地评估自己 先别急着 “爱自己” 让生命欣然舞动 你无法复制乔布斯 符号不是目的 如果一件事发生了 每当我起心动念时 爱出者爱返 理解不是尊重的基础 在没有解决自己的问题之前 “知足常乐” 不是比较 逻辑是无法成为信仰的 买不到的自由 成为诵经者 伤口听不懂大道理 是立场让你不自由 - Unfreedom 天雨大不润无根之草 做自己的神 当心诱惑本身 牛洞冥思录 修罗启示录 让大脑自举 我更喜欢叫它无梦寺 存在主义也许不是解药 出南洋记 2022 的所有答复 没意义的表达 思考的记录 故宫暂行之幻想 极端的比较 解构的终极 舍利子是如何炼成的 心要野 佛教的偏见 文艺青年 我是动物
README.md
Surmon · 2022-01-27 · via Surmon.me

前一周还在上海,重新折腾了一阵子 GitHub 的 README.md profile

看得出来,绝大部分的项目大家都用的是 github-readme-stats 提供的统计图表装饰自己的 profile,包括我之前也是。

项目很棒,但不适用于苛求表达设计的前端,所以我想,有没有可能将设计能力完全开放于他人?

README.md

于是有了 README.md 这个项目。

其实还有一条路是使用 GitHub Actions 执行定时任务,自行维护数据即可,只是有一定的开发成本,还是开箱即用的 “服务” 更加简洁和普适。

先看下我现在的主页:

是啥

说简单点吧:

GitHub README.md profile 允许你定义一个以自己 GitHub username 命名的仓库,并读取此仓库主分支根目录的 README.md 渲染在你的 GitHub 个人主页。

也就意味着,GitHub markdown 支持的最大(UI、编程)能力即是我们可以实践设计(编码)的最大发挥空间。

SVG

原始的 markdown 是无法实现交互、动画、这样的高级渲染的,但 SVG 可以做到,且 SVG 可以被用于 markdown 中的 img 内联。

但在实测过程中发现:

  1. GitHub 对所有 README.md 中引用的外部资源都使用了基于 githubusercontent.com 域名的缓存代理,换句话说,GitHub 不允许自己的主站直接发起任何外部站点的网络请求。
  2. githubusercontent.com 这个域名的 content-security-policy 非常、极其严苛,除去一些限制条件后,仅允许:以 Base64 内联的资源、内联的 CSS 样式,内联的 HTML,且不支持任何类型的 script,总之不能在资源中再引用任何外部资源。

好了,确定好限制之后,我们就知道可以做什么了:

  1. 可以渲染 SVG
  2. SVG 中可以包含内联 CSS
  3. SVG 中可以包含 Base64 格式的图片等媒体资源

以及不可以做什么:

  1. 不支持 SVG 中的 script,即便你写了,script 也不会被执行,所以可以放弃 JS 动画了
  2. 不支持引用任何位置的外部资源,如一张图片、视频、一个 CSS 文件,都是完全不可能的
  3. 不支持 CSS 的动画交互,如 :hover 之类的用户交互行为;因为我们只能通过图片的形式引用 SVG,所以对 markdown 来说,其只负责 “图形的渲染”,而不存在 “图形的交互”

如此,我们便可确定,GitHub 的 markdown 可以引用包含 CSS 动画的 SVG。

HTML

将 SVG 交给用户去实现 “设计” 太不现实了,对大多数用户来说,最好的设计工具一定是最普适、最简单的。

所以可以想到,最完美的设计工具必定是 CSS + HTML,于是我们可以简单实现为基于 foreignObjectSVG<HTML> 渲染机制。

最简单的例子如下:

        
        

12345678910111213

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" ${your_custom_svg_attrs.join(' ')} > <foreignObject width="100%" height="100%"> <body xmlns="http://www.w3.org/1999/xhtml"> <style>${your_css}</style> ${your_html} </body> </foreignObject> </svg>

如此,用户仅需提供 HTML 和 CSS,即可将其渲染为一个可以被 markdown 正常引用的 SVG 图片了。

Vue

到这里,似乎我们忽略了一个点,假设我们需要渲染一个 user top languages 列表,该如何实现?

我们需要循环一整个列表数据,将每一项转换为指定的 HTML DOM 片段,并最终拼接在一起。

如此,我们需要执行 JavaScript 脚本,那么 JavaScript 在什么时机执行?如何优雅地暴露承载脚本的接口?且同时还需考虑 HTML、CSS 接口的存在。

此刻,似乎 Vue 天生就是为此场景打造的。

我们来看一个简单的 Vue SFC component:

        
        

123456789101112131415161718192021222324252627282930313233

<template> <ul class="languages"> <li class="item" v-for="lang in languages">{{ lang.name }}</li> </ul> </template> <script> export default { name: "GitHubTopLanguages", props: { username: { type: String, required: true, }, }, setup(props) { // fetch languages ... return { languages, }; }, }; </script> <style> .languages { padding: 0; } .item { color: red; } </style>

实在是太契合了!

我们将 template 中的模板部分通过在 Node.js 渲染层通过 Vue SSR 渲染为 HTML,并直接输出至 SVG 的 foreignObject 中。

同时我们拿到了用户定义的 Pure CSS 内容,直接消费于 SVG 渲染器即可。

script 则更简单了,Vue SSR 渲染的过程即是执行 script 的过程,自然而然。

Vue SFC 带来的好处可不仅如此,props 的描述能力又恰巧天然可以完整描述一个 component 的 API,虽然只能描述基本类型,但在 README.md 项目中这完全足够且刚好足够了!

最终

最终我基于 Vue > SSR render > SVG render 的渲染机制实现了一套程序并部署在 Vercel serverless,作为一项免费的公共服务提供于外部。

简单的工作流程如下图:

在 Node.js 服务端,我使用 GitHub 的公读 AK 拉取各种 UI 可能需要的数据,并 注入至 Node.js SSR render 时的 Sandbox ,这样即实现了开发者的 “各取所需”,当然背后是基于 GitHub 的 GraphQL API。

相关代码在这里

一个 Vue 组件即一个 template,README.md 项目内置了一些 漂亮的预置模板 ,当然你可以可以通过 template_url template_string 参数 指定你的自定义模板

具体详细的 API 和开发指南可以参考 README.md 项目的 README.md

一些 SVG 图片效果(预置模板):

hello-world

github-contributions-calendar

github-sponsor-button

github-top-languages

TODO

当然接下来还希望可以有一个前端服务,用于用户在 UI 界面编辑、创建自己的自定义模板,及根据简洁的表单直接生成 SVG 图片地址。

希望这个项目对你有所帮助,也欢迎你贡献更多的想法和灵感。

(完)