Hacker News new | past | comments | ask | show | jobs | submit login

There are some key things here that maybe weren't clearly stated in my writeup.

Firstly, the old codebase is TS namespaces, which compile down to IIFEs that push properties onto objects. Each file that declares that namespace is its own IIFE, and so every access to other files incurs the overhead of a property access.

With modules, tooling like esbuild, rollup, can now actually see those dependencies (now they are standard ES module imports) and optimize access to them. In this PR's case, the main boost comes from scope hoisting.

For example, in one file, we may declare the helper `isIdentifier`. In namespaces, we would write `isIdentifier` in another file, but this would at emit time turn into `ts.isIdentifier`, which is slower. Now, we import that helper, and then esbuild (or rollup) can see that exact symbol. All of the helpers get pulled to the top of the output bundle, and calls to those helpers are direct.

That's why modules gives us a boost. There's also more (modules means we can use tooling to tree shake the output, and smaller bundles are faster to load), but the hoisting is the big thing.




Maybe they could update esbuild to be aware of TS namespaces instead?


I think it's the case that modules are the future; but the main focus of this change was not actually performance at all. We've been wanting to be able to dogfood the modules experience (used by most TS devs) for a long time. The fact that it turns out to be so much faster is a really great side effect.


TS namespaces are a really interesting relic of Typescript pre-1.0 in the bad old "jQuery era" before ECMAScript Modules and even before Node CommonJS modules were that dominant and the two most common "module" formats in the browser were "no module at all" and less beloved AMD [RIP]. Typescript namespaces were based on one of the IIFE approaches to "no module at all" smashing a sometimes large codebase into a single global variable, jQuery style.

Most Typescript projects today wouldn't use TS namespaces if you paid them too. It's a backwards "module format" that the modern web and modern Node (and Deno) is trying to leave behind. Several issues and PRs have been filed on Typescript to drop namespaces as a first-class syntax altogether because it unnecessarily confuses newcomers and shouldn't be used in new code in 2022, but there are some major pre-1.0 Typescript projects that still need them for legacy reasons. Typescript itself bootstrapped itself with itself and was one of those large projects with such a legacy dependency, hah. (From the PR you can see precisely how much tech debt that this has left in Typescript's own codebase!)

So, long story short: esbuild doing a bunch of work to support jQuery-era IIFE patterns is maybe not the best use of esbuild developers' time in 2022.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: