Having written a production compiler in a previous lifetime, and talked with developers over the years since then, it is clear the difference that knowledge makes in their day-to-day programming.
Writing a compiler isn’t much harder than writing an interpreter, if at all.
Assuming your language can be parsed without running it (Perl, for instance, cannot, in general. See https://www.perlmonks.org/?node_id=663393), it is just a matter of doing that and emitting code for every statement, plus some bookkeeping in order to fix up branches. If the language you are compiling is simple, that’s not hard to do.
The result will not be the fastest possible, but it will be compiled code, and it will be faster (sometimes significantly so) than interpreting the program.
We don’t say “Web applications are large and complex”, either.
Just as you can start simple with a web application and, if needed, grow it, you can start with a simple compiler and, if needed, grow it.
(And, on current hardware, I think the complexity of the language matters less than it used to. Single pass languages such as pascal still are easier targets, but computers have plenty of RAM, so fixing up things is easier than it used to be.
Why Study Compiler Construction?
A compiler is a large, complex program. Compilers often include hundreds of thousands, if not millions, of lines of code, organized into multiple subsystems and components. The various parts of a compiler interact in complex ways. Design decisions made for one part of the compiler have important ramifications for other parts. Thus, the design and implementation of a compiler is a substantial exercise in software engineering.
A good compiler contains a microcosm of computer science. It makes practical use of greedy algorithms (register allocation), heuristic search techniques (list scheduling), graph algorithms (dead-code elimination), dynamic programming (instruction selection), finite automata and push-down automata (scanning and parsing), and fixed-point algorithms (data-flow analysis). It deals with problems such as dynamic allocation, synchronization, naming, locality, memory hierarchy management, and pipeline scheduling. Few software systems bring together as many complex and diverse components. Working inside a compiler provides practical experience in software engineering that is hard to obtain with smaller, less intricate systems.