The things you are describing are what I’m calling simplistic syntactic transformations that don’t modify semantics.
As the slightest taste of the sort of thing I’m talking of:
• Any sane developer would be happy to rewrite `let x=a.c;a.b(x)` as `a.b(a.c)`, but that changes semantics (accessing a.b and a.c could have side-effects) and so no tooling short of Closure Compiler with appropriate hints is willing to do it. This sort of pattern is extremely common. End result: readable code is bigger than it should be.
• Tools like Terser are, on a good day, willing to inline functions that are used only once; but they only do this on free functions. Use methods, and they’re useless. Again, Closure Compiler with appropriate hints can do a bit better. End result: abstractions and good factoring are expensive, producing bigger and slower code.
• In fact, this generalises: state-of-the-art JavaScript tooling can do a little where everything is on the stack, but use objects and methods and such and they’re stymied. Inlining. Dead code removal. Name mangling. All things that work inside modules, function bodies, &c., but don’t work once you use objects and properties. Closure Compiler is the only tool that can do anything at all here, which is a real shame. Someone really should have built something like it atop TypeScript by now.
Going back a few years to where this was more prevalent and important, there was a significant difference of philosophy between Babel and Bublé, webpack and Rollup. Babel said “compile new constructs into something that does precisely the same thing”, at a significant code size, performance and readability cost, whereas Bublé said “compile new constructs into something small and fast that almost always does the same thing”, at a slight scope and compatibility cost. Webpack similarly did a robotic port of modules at a significant code size, performance and readability cost, whereas Rollup said “let’s unravel the now-unnecessary abstraction and produce efficient code”. In my view, Babel and webpack are profligate, doing the easy thing rather than the sensible thing; and Rollup does the sensible thing, at only a very slight compatibility cost (and Bublé did the mostly sensible thing, though at a much higher compatibility cost, but we don’t need it any more).
JavaScript engines are extraordinarily good at what they do, given the handicap that they start with. But if you can give them better code, they’ll fare better, especially before JITting occurs. I’m talking about giving them better-optimised code. Also about shipping smaller bundles.
Also, partial execution: if you haven’t worked with native code compilation, you might not realise just how good those things are, especially where mathematics is involved. I love the fact that, in benchmarking a Rust Base58 decoder I wrote recently, I had to use test::black_box on the input, or else decode_u64("jpXCZedGfVQ") evaluated to Ok(0xFFFFFFFFFFFFFFFF) at compile time (and it wasn’t even a const fn!). And Rust is only going further with varieties of guaranteed const evaluation. Prepack tried, but Facebook gave up on it for some reason. For me, I really just want something like Zig’s comptime in JavaScript (well, a compile-to-JavaScript JavaScript variant), as guaranteed partial execution.