The most naive solution (tracing a line to each tile and checking for collision) introduces weird artifacts, like illuminating a single cell 8 tiles away from a window when you're 45 degrees away from the window, that I couldn't persevere through the temptation of getting that perfect.
Then I realized this is just a taste of why all gamedev is hard. Is $GameMechanic going to be more fun implemented like $this or like $that? Well, you can't just git-branch and try both because both options are non-trivial. And it's easy to procrastinate by working on things off the critical path of finishing the game because that is what's hard.
Turns out it involves an impressive amount of visionary power + ability to laser-focus on the Hard Stuff That Matters to build a game. And I'll always respect the super heroes out there that are able to finish one. I suppose it's not so different from writing a book.