@ryo I don't like PHP but I didn't have a good alternative for a long time either
My solution to this was to use luvit (luajit + async io) and make my own "framework" by inlining lua in the html and calling it really simply like
local html = "<span>1 + 1 = <b>{{{ return 1 + 1 }}}</b></span>"
html:gsub("{{{(.-)}}}", function(code) return load(code, "", "t")() end)
Basically no effort. No bloat. LuaJIT is extremely fast. Full control
@ryo in JS you can use await to inline promises so you get none of that. To download a json file:
let json = await(await fetch("/data.json")).json();
In Lua I guess you could set up something using coroutines (cooperative sharing, basically) but I've always just used callbacks. I make a function that wraps the callback with some logic to handle errors properly so I don't get the .then.catch(reject) hell that I got in JS before learning about await