Posted on 2/24/2025, 4:30 PM
Recently I've really wanted to have somewhere to put code, or show off a side-project or experiment. I've also wanted to do more than dabble with generative AI. I'd really like to embrace what generative AI has to offer. So, I figured building a personal site would be a great starting point for building up the skill of working with LLMs. So I'll give a surface-level overview of my expectations, my experience, any roadblocks, and next steps.
Intro
Now, we all know LLMs are very much NOT perfect. This is okay though. My goal is not to build the perfect site from start to finish. My goal is to get the first 80% out of the way. Once that's done I'll only have the last 80% to do in a more meticulous manner. See, for me the impediment to getting a project started is the boilerplate. When you already have a working system, it's really easy to jump into it and continue where you left off. That's just not the case when you have nothing. Feel free to skip directly to my pros and cons!
Working With ChatGPT
In my mind, ChatGPT is like a very eager junior engineer who tries their hardest to get your request correct on the first try, without additional input (unless you tell it to ask for more). I just want something working. I think we're a match!
Starting Out
In my head I already had a list of a few requirements for the site ready to give to ChatGPT:
- Create a site with a few specified pages (home, blog, bookmarks)
- Be fun and whimsical in our styling
- Use different backgrounds and colors per page to make them feel discrete
From there, I had ChatGPT get to work on building the initial layouts. Keeping it simple we focused on just the overall design of each page. We iterated on this for some time, with me spinning up a Caddy server to preview and validate ChatGPT's creation. Building from a somewhat vague description and suggesting more specific elements for each page worked quite well for ChatGPT. It'd build upon what it had, generally keeping the code the same and getting my requests mostly correct.
A few issues I had during this stage were:
- ChatGPT took many attempts to correct a collapsible, mobile-first menu
- Some code changed quite a bit between requests, requiring some manual review
Ultimately not a bad experience! I probably iterated with ChatGPT for a handful of hours here. I was most impressed by its ability to generate SVG for the background image. It wasn't just that it generated SVGs that was impressive, but that it defined the SVG inline in the CSS with proper syntax.
Adding SSG Functionality
The next thing I wanted from ChatGPT was a way to manage the content on the site. Time to get in the weeds! So I started out by asking ChatGPT for some recommendations for static site generators that it feels confident working with. One feature I really wanted was for every page to be able to be output as a single HTML page in any directory I choose. ChatGPT suggested:
- Jekyll
- Hugo
- 11ty (Eleventy)
So this was nice. I was able to get a few suggestions for a static site generator to use. Two of which I knew, but Eleventy was brand new to me. I continued by prompting ChatGPT to ask it exactly how it planned to accomplish my goal of flat output files. I decided Eleventy seemed perfect for my use-case after hearing ChatGPT's explanation and doing some light digging through each SSG's documentation. Not only does Eleventy allow arbitrary output files to enable the flat output files like I want, it also has the input file types that I was secretly hoping for. Eleventy supports Nunjucks templates, which feel very comfortable if you've been in the JavaScript ecosystem for a bit, and the template syntax is simple, battle-tested, and flexible. Also, plain HTML support is there for any random page I feel like throwing on the web.
Of course it didn't go 100% perfect. The default files ChatGPT gave me did not actually parse properly on the first try of a npm run build
. I had to add a date parser, a filter for rendering dates, and a filter for sorting my navigation elements in the order I'd like. The majority of time on this step was spent with me manually splitting up the original layout files into njk
templates. ChatGPT kind of tried to do it for me but honestly it wasn't the best, and I thought it would just be faster to do it manually. Who knows if I'm right, but since I was already familiar with the templating engine it didn't take me long at all.
After all this I ended up with a directory that looks like this:
.
├── Caddyfile
├── eleventy.config.mjs
├── package-lock.json
├── package.json
└── src
├── _includes
│ └── layouts
│ ├── base.njk
│ ├── blog-post.njk
│ ├── blog.njk
│ ├── bookmarks.njk
│ └── home.njk
├── blog
│ ├── index.njk
│ └── posts
│ └── <timestamp>-building-a-personal-website-with-chatgpt.njk
├── bookmarks
│ └── index.njk
└── home
└── index.njk
Posting CRUD
So I'm sitting here with a static site generator spun up exactly how I want and I'm thinking to myself, "I guess I need a way to actually write the content now." So back to ChatGPT I went, because like I mentioned earlier, this is the stuff I don't feel like building myself right now. I don't mind refactoring later, but getting a working prototype to actually refactor is huge.
So I continued the session by telling ChatGPT I wanted to talk about authoring content and building a new sub-package that would be a tool to author a blog post. It should generate the template files with proper formatting and timestamps. I iterated on this with ChatGPT for some time, but the end result was actually pretty eye-opening.
The server generated by ChatGPT was totally workable, though it does have several glaring security issues. But you know what? This is okay. This is single-user software. Not to beat a dead horse here, but just getting the first 80% is our goal here. Just for fun, have a look at one fun vulnerability (hint: path traversal):
// New DELETE route for removing a post.
app.delete("/delete-post", (req, res) => {
const fileName = req.query.file as string;
if (!fileName) {
return res.status(400).send("Missing file parameter");
}
const filePath = path.join(postsDir, fileName);
fs.unlink(filePath, (err) => {
if (err) {
console.error(err);
return res.status(500).send("Error deleting file");
}
res.json({ message: "Post deleted successfully" });
});
});
I spent the most amount of time iterating on a suitable post authoring interface with ChatGPT. I had to fix TypeScript handling, fix CORS issues due to server and frontend using different ports (Caddy to the rescue again), and try to work through different WYSIWYG editors eventually settling on a much better custom solution.
I feel like not many years ago (really it's probably like 10 years ago) there were many WYSIWYG options. Now it seems most require a license key or convoluted setup. I wanted to use a prepackaged solution, but eventually relented and suggested ChatGPT to just use a contentEditable
div. And honestly? It's perfect. The issue I was having with other editors was getting a view of the raw HTML that also preserves custom classes when going back to WYSIWYG mode. It's just not simple. You know where it is simple though? In a contentEditable
div.
CreatePost.tsx
component and I was able to test QuillJS, TinyMCE, CKEditor, and TipTap within the span of an hour or so. That is real value in my eyes. Once I realized that the contentEditable
div was my golden ticket I tasked ChatGPT with building a toolbar for WYSIWYG interactions. I ended up with what feels like a real blogging platform, so it's really blowing my mind that I threw this together so quickly with ChatGPT!
Wrapping Up
I think I learned a lot taking this little trip. I learned ChatGPT is actually not too bad now. Maybe I just happen to be trying something that is common enough for ChatGPT to excel, but my experience was great. I ended up with an interface that feels great, looks great, and most of all functions! I have a starting point that I can build from, and that's really what I was asking for.
Of course it wasn't all roses. I'll try and summarize the pros and cons that I observed in this experiment.
Some good things I can say about my experience:
- ChatGPT's initial project setup was mostly on point
- You can test different implementations (WYSIWYG editors in my case) very quickly when you know what you are looking for
- You really can get a prototype knocked out in a weekend being assisted by AI
Some bad things I can say about my experience:
- There were still issues to fix with the generated code. Of course I was able to debug them, but I think it is mostly due to my experience with the ecosystem.
- ChatGPT sometimes removes or forgets functions it already defined, so when overwriting a file I'd do a quick review of the (graphical) diff and manually merge at times
- I had to remind ChatGPT to use React best-practices for its function components (Properly using
useEffect
, et al) - When dealing with a large file (Which
CreatePost.tsx
became) ChatGPT responds with code listings very slowly. I mean, still faster than I would write it probably, but somehow still slow enough to be annoying. - Trying to have ChatGPT refactor the
CreatePost.tsx
was disastrous so I quit the attempt and will refactor it myself later (Famous last words)
I think ChatGPT would have really shined if I had a more clear picture of exactly what I wanted, rather than just the vague ideas I had. Meaning, I think I would have had even more success if I actually wrote a design document that described each and every detail for each and every step. ChatGPT is good, but it does not read minds.
What's Missing
There are a few things I'd still like to iterate on. Here are a few ideas I hope come to fruition:
- Add editor support for images. I'd love to add an image in here showing the editor interface. Perhaps the next post.
- Have separate
createdAt
,postedAt
, andupdatedAt
dates. Currently I havecreatedAt
andupdatedAt
, but would like to be able to have decent draft support.
Final Words
I think LLMs are pretty cool. I think they are definitely a game-changer. Being able to get a project going is worth a lot to me, and my experience building an editor shows me the potential in the software development space. I think embracing AI (but not relying on it) is going to be critical in the future. However, knowing what you're doing and being able to debug is still important today.