Yeah, even if it's written with frontend web tech, there's definitely a different set of skills needed for extension devs compared to the skills needed by CRUD app frontend devs.
There's some extra code in the project I handed you, because it's built from a template that I used to start some of my freelance Chrome Extension projects from back around the time MV3 was originally released. I wouldn't get too lost trying to read into what everything does. Probably 80-95% of what's in that template is not pertinent to the example.
Q&A:
Q: "Is there no need for anything in the serviceWorker.js file?"
A: It's just along for the ride as part of the template in my example.
Q: Is the serviceWorker.js file considered better practice than background.js?
A: The "background.js" file you're talking about is just an arbitrarily-named Javascript file defined as the "service worker" within manifest.json. You could call it "coffee.js" and as long as that's what you tell the manifest file says you're looking for as a service worker, it will work. The tutorial video you referenced seems to have called this file "background.js", which smells a little off to me since it's definitely different from the background script we used to have in MV2 extensions. To each their own, I suppose.
Q: "Why isn't anything within content.js wrapped around a chrome api call, like chrome.runtime.onMessage.addListener?"
A: You don't need that for content scripts. With a handful of caveats, you can generally think of a content script as "just a script running on the page". You could theoretically have different content scripts match different pages. In practice, most commercial browser extensions err on the side of having one content script that acts as the sole entry point. Maybe two if they want to accommodate a special case (e.g., for communication/DOM manipulation when their extension runs on their own site).
Q: "the tutorial I was following on YouTube" A: I skimmed this. It feels like a pretty awkward patchwork mix of Javascript from different eras and traditions. Wrapping the entire content script in an IIFE feels very much straight out of 2010. It's pointless here since the whole purpose of that technique was to avoid variable name collisions with other scripts, but content scripts run in an "isolated world" by default where these collisions wouldn't happen anyway (not to mention that the "var" keyword isn't really in widespread use anymore). Functions like getElementsByClassName and getElementById are usually not preferred in extensions compared to querySelector and querySelectorAll, as the latter two are much more expressive and powerful. Generally the only time you'd prefer the former two is when you want to squeeze every last drop of performance out of a simple element query that must be called frequently, e.g., in response to page mutations. Listening to him talk about chrome.storage.sync, it wasn't clear to me that he was aware of its tiny storage quota and that chrome.storage.local exists as the "standard" storage area. All-in-all, it felt like some regular dev who read some docs and maybe wrote 1 extension is now teaching other devs how to do it. Probably not unprecedented for freeCodeCamp.
Q: "the GPT answers (although those were very meh) I got suggested that"
A: Yeah, ChatGPT is actually pretty overrated for learning new things. In order to write a prompt that's useful, you usually have to have lead it with some domain knowledge. But if you had that knowledge, you wouldn't have to ask. Catch-22. My bet is that others will eventually catch onto this as well (just as the world at large finally caught on that NFTs are essentially worthless), and this bubble of excess hype around AI will pop. There are some cool/useful use-cases, but it feels oversold right now.