使用无服务器绘制你的 Github 个人资料
我经常被问到“我应该做什么?”或“这些想法从何而来?”之类的问题。我之前讲过我是如何产生想法的。要点是,把你所有的想法,无论大小,都写下来。
这对于演示来说非常有效。但是当你想学习一些更实用的东西时该怎么办呢?比如组建一个项目或尝试更多的工具。
我提倡的一件事是构建工具。你想用的工具。能帮你解决问题的工具。没错,为自己打造。
这有很多好处:
- 你对这个想法很感兴趣。
- 您可以学到很多东西来解决您的问题。
- 您可以向潜在雇主/客户展示一些与众不同的东西。
最后一点可能特别有用。有趣的业余项目可以成为很好的谈资。我已经记不清有多少次因为我的Github 个人资料而收到评论了。因为招聘人员会查看它,并在贡献图表中看到一幅图像。
今天,我们将介绍我去年做的一个项目。“ Vincent van Git ”教你如何绘制你的 Github 贡献图。我会讲解“是什么?”、 “为什么?” 以及“怎么做?”。
什么?
如上所述,“Vincent van Git” 可以帮助你绘制 GitHub 贡献图。它是一个 Web 应用,可以生成一个 Shell 脚本供你在机器上运行。最终,你会用绘制图表的提交来填充图表。随着时间的推移(大约 3 个月),图表会发生变化,你需要重新创建它。
为什么?
这部分分成两部分,“为什么要这样做?”和“为什么要这样做?”哈哈。
首先,在创作“Vincent”之前,我一直使用“ gitfiti ”这个包。它是一个命令行工具,可以用来在贡献图上涂鸦。它使用 Python 语言,可以用数组来绘制图像。
KITTY = [
[0,0,0,4,0,0,0,0,4,0,0,0],
[0,0,4,2,4,4,4,4,2,4,0,0],
[0,0,4,2,2,2,2,2,2,4,0,0],
[2,2,4,2,4,2,2,4,2,4,2,2],
[0,0,4,2,2,3,3,2,2,4,0,0],
[2,2,4,2,2,2,2,2,2,4,2,2],
[0,0,0,3,4,4,4,4,3,0,0,0],
]
如果你眯起眼睛,就能看到那只小猫。但是,它本身就是一个非视觉化的工具,却能带来视觉效果,这让我用起来很棘手。别误会,它是个很棒的工具。但我一直想用一种视觉的方式来创作。
现在,我可以创建一个前端来生成该数组,然后将其与 gitfiti 一起使用。但是,为什么要止步于此呢?为什么不尝试从头开始创建我自己的版本呢?
这引出了我们的第二个“为什么”。因为这里有学习各种不同工具的机会,也有机会尝试新事物。这又回到了我们在引言中提到的观点。通过一些非常规的副业项目,你可以解决一些非常规的问题。这将帮助你提升解决问题的能力。
在深入探讨学到的东西和方法之前,以下是一些我尝试过的东西。
它们不太可能出现在教程式的 CRUD 应用中。这并不是说我们刚开始学习时不应该遵循这些教程。但是,当我们开始思考“下一步是什么”时,勇于尝试是有好处的。
如何?
是时候聊聊“怎么做?”了。我会把这部分分成几个小节来讲。我不会深入探讨,但我会讲解一下某些事情是如何实现的。也就是所谓的讨论要点。
电子
我脑子里有个想法,想electron
为“文森特”开发一款应用。一款桌面应用,我可以打开它,画点东西,然后点击“提交”。虽然最终没能实现,但这就是我的开始。
这是项目的关键部分。我选择使用electron
是因为我想开发一个可以在用户机器上使用 Node 的 React 应用。这样就能在 内部调用“git”了electron
。
我之前没怎么尝试过这个想法,但这是一个熟悉ipcRenderer的机会。它是一种在 Reactrenderer
和 Nodemain
进程之间进行通信的方式。这意味着你可以在 React 世界中点击一个按钮,然后在 Node 世界中触发一个函数。
我整理了这个代码库,演示了如何实现这一点。在 OSX 上,如果你在前端按下消息按钮,它会使用say
命令行读出消息。
前端
我很清楚自己想要什么。我们需要一个类似于 Github 贡献图的网格。用户可以用指针来绘制网格。每个单元格可以是透明的,也可以是四种绿色中的一种。最终的网格效果如下。
这些类型的交互和 React 的棘手之处在于,我们不想在每次绘制时都更新状态。那样会导致大量的重新渲染。我们可以用 refs 来追踪正在发生的事情。
创造一些不同的东西会挑战我们以不同的方式使用我们常用的工具。像 Vincent 这样的工具非常适合处理 DOM 操作和 React。我也在其他项目上做过类似的尝试,比如“PxL”。
项目的这一部分是关于生成我们之前提到的数组的。我们为用户提供了一种无需手动输入就能生成 0 到 4 的数字数组的方法。
使用无服务器进行 Web 抓取
现在,“Vincent”之所以能够实现,是因为空提交。它的工作原理是,我们会生成数百个空提交,并将它们提交到您选择的存储库。这些空提交会显示在贡献图中。
如何获得四种不同的绿色?这取决于提交次数。例如,假设你每年的最大提交次数是 100 次。那么为了获得 4 个级别,我们可以分别使用每天 400、300、200 和 100 次提交。这样就能生成四种不同的绿色。
我们最需要的是用户名的最大提交次数。为了获取这个信息,我们进行了一些检查,然后抓取 Github 上的活动页面。在“Vincent”中,我们要求输入用户名、分支名称和仓库名称。“Vincent”会检查这些信息是否存在,并且为空,然后再抓取提交信息。
我们这里大概有 4 到 5 个请求。这时无服务器就派上用场了。我们可以把这些请求放到Netlify 函数里,这样前端只需要发出一个请求。
这是该函数最重要的部分。在这里,我们向“贡献”页面发出请求。然后,我们用它cheerio
来抓取过去一年中提交量最高的代码。
const getCommitMultiplier = async (username) => {
// Grab the page HTML
const PAGE = await (
await fetch(`https://github.com/users/${username}/contributions`)
).text()
// Use Cheerio to parse the highest commit count for a day
const $ = cheerio.load(PAGE)
// Instantiate an Array
const COUNTS = []
// Grab all the commit days from the HTML
const COMMIT_DAYS = $('[data-count]')
// Loop over the commit days and grab the "data-count" attribute
// Push it into the Array
COMMIT_DAYS.each((DAY) => {
COUNTS.push(parseInt(COMMIT_DAYS[DAY].attribs['data-count'], 10))
})
// console.info(`Largest amount of commits for a day is ${Math.max(...COUNTS)}`)
return Math.max(...COUNTS)
}
您也可以创建一个本地版本并解析响应。尝试使用您自己的用户名发出该请求。
生成 Shell 脚本
接下来,我们需要一个 Shell 脚本来推送所有生成的空提交。这部分内容是在循环中创建一个长字符串。对于每个提交,我们都会根据绘制级别分配一个日期和多个提交。
第一部分需要使用luxon
(我们不再需要了moment.js
)来将日期与提交进行匹配。日期相关的一些数学运算在前几次尝试中有点棘手。但一旦搞清楚了,就大功告成了!
const processCommits = async (commits, multiplier, onCommit, dispatch) => {
const TODAY = DateTime.local()
const START_DAY = TODAY.minus({ days: commits.length - 1 })
let total = 0
let genArr = []
for (let c = 0; c < commits.length; c++) {
const LEVEL = commits[c]
const NUMBER_COMMITS = LEVEL * multiplier
total += NUMBER_COMMITS
genArr.push(NUMBER_COMMITS)
}
// Dispatch a message.
dispatch({
type: ACTIONS.TOASTING,
toast: {
type: TOASTS.INFO,
message: MESSAGES.TOTAL(total),
life: 4000,
},
})
// Loop through the commits matching up the dates and creating empty commits
for (let d = 0; d < genArr.length; d++) {
// Git commit structure
// git commit --allow-empty --date "Mon Oct 12 23:17:02 2020 +0100" -m "Vincent paints again"
const COMMITS = genArr[d]
if (COMMITS > 0) {
const COMMIT_DAY = START_DAY.plus({ days: d })
for (let c = 0; c < COMMITS; c++) {
onCommit(COMMIT_DAY.toISO({ includeOffset: true }))
}
}
}
}
一旦我们准备好所有提交数据,就可以生成该脚本了。它是一个基于提交日期、用户名、分支等信息的长字符串。
const generateShellScript = async (
commits,
username,
multiplier,
repository,
branch,
repoPath,
dispatch
) => {
let SCRIPT = `mkdir ${repoPath}
cd ${repoPath}
git init
`
await processCommits(
commits,
multiplier,
(date) => {
SCRIPT += `git commit --allow-empty --date "${date})}" -m "Vincent paints again"\n`
},
dispatch
)
SCRIPT += `git remote add origin https://github.com/${username}/${repository}.git\n`
SCRIPT += `git push -u origin ${branch}\n`
SCRIPT += `cd ../\n`
SCRIPT += `rm -rf ${repoPath}\n`
return SCRIPT
}
抛弃 Electron
“等等。我以为你想用 Electron?” – 读者
我做到了。
我进展得相当顺利。不过,也遇到了一些阻碍,不过没关系。问题在于通过 Node 推送提交。这需要很长时间,有时还会耗尽缓冲区。另一个问题是,我无法以清晰的方式将这些信息传达给前端。
这就是我开始编写 Shell 脚本的原因。我开始深入研究electron-dl
,突然electron-store
灵光一闪:“这应该放在 Web 上。”
我只研究过如何为不同平台打包桌面应用,看起来还不错。但是,从测试和反馈来看,Windows 系统已经存在一些问题。
还有可用性因素。这不是你每天都会用到的工具。而且网页比下载安装应用程序等更容易访问。
我决定在此时放弃 Electron。而这正是 React 的强项。因为我已经为前端创建了各种构建块,所以将它们移植到 Web 应用中非常轻松。
是不是浪费时间?不!
虽然我最终没有用到Electron,但这并不意味着尝试是浪费时间。事实上,我electron
在短时间内学到了很多东西,这很棒。
用户界面的乐趣
在这个阶段,我有一个可行的概念证明🙌
现在我可以好好利用它了,把所有方便用户的功能整合起来。一个可配置的表单,保存和加载绘图、动画等等。
这些是令我印象深刻的事情。
配置
我需要表单进行配置。用户可以在其中填写用户名、分支和仓库信息。同时,我还想创建一个滑动抽屉效果。
对于表单处理,我本来可以自己实现formik
或创建表单处理。但我决定尝试一下react-hook-form
,结果很棒。这又是一个尝试不同事物的机会。滑动抽屉的外观如下。
构建此类功能的另一个好处是,你可以寻找重构的模式。这个抽屉菜单已经成为一个可复用的组件。我把它复用到应用右侧的“信息”抽屉菜单上。
声音的
我喜欢在我的项目里添加一些奇思妙想。这是人们与我联系在一起的东西。声音是必须的,我用一个快速自定义的钩子将一些按钮点击和操作与音频连接起来。
import { useRef } from 'react'
const useSound = (path) => {
const soundRef = useRef(new Audio(path))
const play = () => {
soundRef.current.currentTime = 0
soundRef.current.play()
}
const pause = () => soundRef.current.pause()
const stop = () => {
soundRef.current.pause()
soundRef.current.currentTime = 0
}
return {
play,
stop,
pause,
}
}
export default useSound
但真正有趣的是绘制网格时的声音。在“跟 Jason 学习”上看到 Tone.js 之后,我就想再多试试看。这看起来是个好机会。不同的级别会发出不同的音符。擦除会发出沉闷的音符。
祝酒词
该应用需要一些小的 toast 组件来让用户了解正在发生的事情。例如,确认保存或告知用户正在生成提交。
我本来可以尝试一些现成的组件。但是,我不记得自己在开源组件中做过什么。这感觉是个不错的机会。用一点 React 和 GreenSock,我做了一个很棒的 Toasts 组件。创建 Toast 组件的妙处在于,它能让你更多地思考组件本身。你需要使用状态来触发创建。但是,你并没有将状态与 Toasts 绑定。这部分代码值得检查一下。
动画片
我喜欢在某个地方添加一些动画。而且这是我自己的项目,我可以放任意多的动画。
还有什么比生成 shell 脚本时添加加载动画更棒的呢?在琢磨了一番项目名称和编写代码之后,我最终选择了这个。
一些音频和 8 位风格的音乐使它更加完美!
Zip文件
如果你尝试为用户下载shell脚本,系统会提示你安全警告。我以前从未遇到过这种情况,这对我来说很新鲜。
直播中的观众建议尝试一下jszip
。这巧妙地解决了一个问题。jszip
我可以为用户打包一个文件README
和shell脚本,并让他们下载一个zip文件。这样,用户也能获得运行该文件的指令。
const FILE = new zip()
FILE.file('vincent-van-git.sh', SCRIPT)
FILE.file('README.md', README)
const ZIP_FILE = await FILE.generateAsync({ type: 'blob' })
downloadFile(ZIP_FILE, 'vincent-van-git.zip')
这很方便,也是我尝试一些我以前没有尝试过的新事物的另一个机会。
就是这样!
我部署了它,制作了一个简短的视频,并分享了它!所有代码都是开源的。你可以用这个应用通过无服务器的方式将提交内容写入你的 Github 个人资料。我从创建“ Vincent van Git ”的过程中学到了很多东西。它帮我解决了一个问题。它提供了一些技巧供我尝试,也让我有机会尝试不同的软件包。
这里有什么可行的建议?
为自己动手做。这是切实可行的建议。做一些你觉得有用的东西。做一个工具或你感兴趣的东西。它可以为你解决某个特定的问题,也可能为别人解决某个问题。它还能给你一个学习和尝试新事物的渠道。
为自己做。
鏂囩珷鏉ユ簮锛�https://dev.to/jh3y/paint-your-github-profile-with-serverless-15i7