Dynamic Github profile with Bun and Typescript
In a recent article, I discussed transforming a GitHub profile into an interactive space with icons, badges, and dynamically updated blog posts using Python scripts and GitHub actions.
After sharing my work in the “r/javascript” community on Reddit, I received serveral positive feedback and upvotes. I chose to post in this community due to my familiarity with JavaScript and TypeScript. After several hours, moderators removed my post because it wasn’t directly related to JavaScript. They made the right decision, and I appreciate their careful moderation of the community. This made me rethink my approach and think about using a language that would better connect with the audience, given the simplicity of the script’s principle: fetching feed URL, parsing it, and writing the response to the README.md file, along with automatic updates using a cron job on GitHub action.
I decided to explore using JavaScript or TypeScript for this idea. While JavaScript would have been sufficient, I opted for TypeScript because of its enhanced safety and the overall enjoyment it offers during development—for me, it’s more fun to work with than JavaScript.
Choosing a runtime was the next consideration. With options like Node.js, Deno, and Bun available, I choose on Bun. Because the runtime mainly executes the script, Bun seemed like the perfect choice. It’s fast, simple, and allows running JavaScript or TypeScript without needing compilation steps.
Let’s set up and implement the code to see how it works.
Firstly, ensure that Bun is installed on your machine. There are several ways to install it, all of which are outlined on the Bun website’s Installation page.
Bun undergoes improvements regularly and changes rapidly. You can ensure you’re using the latest version of Bun by executing the command: bun upgrade
.
In the project, you can initialize Bun by using the command: bun init
, which will generate some files for you. Here is an example of the folder structure after running bun init
:
❯ tree
├── bun.lockb
├── node_modules
├── package.json
├── README.md
├── src
│ └── index.ts
└── tsconfig.json
In my case, I prefer to add it manually for more control.
As I’m using TypeScript, I need to add @types/bun
to work with TypeScript typings. Run the command:
The tsconfig.json
file is also necessary for TypeScript. You can either use the recommended tsconfig.json
provided by Bun or generate one. It’s minimal enough and follows best practices. Here is my tsconfig.json
:
I specify "include": ["src/**/*.ts"]
to tell TypeScript to compile all .ts
files within the src
folder, simplifying TypeScript’s server checking and compilation processes.
Next, I’ll use the rss-parser library from npm to parse the feed atom.xml
from my blog. The principle of this library is similar to the one I used in Python, called feedparser.
Here’s how my package.json
looks:
I use "type": "module"
to write the code in ESM.
The script "readme": "bun src/feed.ts"
runs the TypeScript script I will write later.
Don’t forget to add node_modules
to .gitignore
.“
Now it’s time to write the script feed.ts
.
I’ll use rss-parser
to fetch the feeds from atom.xml.
;
;
;
;
/**
* Fetches and parses the feed from the provided URL.
* @param {string} url - The URL of the feed.
* @returns {Promise<string[]>} An array of formatted feed entries.
*/
;
/**
* Formats a feed entry into a string.
* @param {Entry} entry - The feed entry to format.
* @returns {string} The formatted feed entry.
*/
;
Parsing the URL with rss-parser
is quite simple:
;
;
It returns a response in JSON format. Here’s an example of the response:
This response is already sorted by the date of the post. With this response, I can easily filter and format it according to our requirements.
The remaining code reads the current README.md file, writes the feeds found above, and inserts them into comments in the README file.
Here is the code:
;
;
// Since I'm using ESM syntax, I can use the top-level "await" here.
await ;
Alright, the script is complete. You can find the full code here.
Next, let’s move on to the final step: Configuring the GitHub action.
It’s essentially the same process as I did in the previous article with Python. The only difference is replacing the Python implementation with Bun. Here’s the code:
name: Fetch latest posts from blog for README
on:
push:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- uses: actions/cache@v4
name: Configure bun caching
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ matrix.bun }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-${{ matrix.bun }}-bun-
- run: bun install
- run: bun run readme
- name: Commit and push if changed
run: |-
git diff
git config --global user.email "${{ vars.USER_EMAIL }}"
git config --global user.name "${{ vars.USER_NAME }}"
git add -A
git commit -m "chore: update blog posts" || exit 0
git push
In this scenario, I might not require the caching step for Bun.
- uses: actions/cache@v4
name: Configure bun caching
with:
path: ~/.bun/install/cache
key: ${{ runner.os }}-${{ matrix.bun }}-bun-${{ hashFiles('**/bun.lockb') }}
restore-keys: |
${{ runner.os }}-${{ matrix.bun }}-bun-
bun install
is already sufficiently fast. I’m including this for best practice.
The GitHub Action will execute the command bun run readme
to update the README and create a new commit to reflect the changes.
In summary, I’ve demonstrated how to enhance your GitHub profile using Bun and TypeScript. This straightforward alternative to Python provides a simple method for adding dynamism to your profile. You can find all the code from this article in this branch
For now, I’ve decided to keep the Python version on my main branch because it’s easier to set up.
I hope it helps. Feel free to read the comments or provide feedback on my medium post.
Happy coding!
Enjoyed this article? For more technical content on Typescript or backend development, stay updated by following my blog through RSS feeds
You can also read my other articles on tduyng.medium.com