Rust Is the Future of JavaScript Infrastructure
leerob.io
leerob.io
I'm not sure what the point of my post is, other than to vent. I guess sometimes I just wish we would get rid of JavaScript entirely and switch to a sane language with sane build tools.
Every tool is attempting to dethrone the competition, coming up with yet another way to do the same simple yet infinitely elusive fucking goal: render a website.
The whole ecosystem is fucked
Edit: it seems I don't have to wonder. Type coercion is one of the worst features IMO, and coincidentally one of his regrets:
> "One of the notorious ones was, ‘I’d like to compare a number to a string that contains that numeral. And I don’t want to have to change my code to convert the string to a number, or the number to a string. I just want it to work. Can you please make the equals operator just say, Oh this looks like a two, and this looks like a string number two. They’re equal enough.’"
> "And I did it. And that’s a big regret, because that breaks an important mathematical property, the equivalence relation property… It led to the addition of a second kind of equality operator when we standardized JavaScript.” One of the people who helped standardize JavaScript was Guy Steele, one of the co-creators of Scheme. “Guy said, ‘Don’t worry about it. There are Lisps that have five kinds of equals operators. We’ll just add another one.'"
https://thenewstack.io/brendan-eich-on-creating-javascript-i...
> If COPY can't be done properly, then neither can EQUAL. And, in fact, that's the case. There is no uniquely determined equality function for complex structures--there are only arbitrary ones.
What Steele says about equality is true for Scheme. Everyone has seen the famous "Wat" video of adding "{} + {}" in Ruby or JS. But no one ever mentions Scheme or Lisp:
scheme@(guile-user)> (eq? "test" "test")
$1 = #t
scheme@(guile-user)> (eqv? "test" "test")
$2 = #t
scheme@(guile-user)> (define x "test")
scheme@(guile-user)> (define y "test")
scheme@(guile-user)> (eq? x y)
$3 = #f
scheme@(guile-user)> (eqv? x y)
$4 = #f
Of course, if you read the RxRS specs then it's all documented and to be expected. But the same is true for JavaScript. As much as I hate typing the "===", there is precedence.> breaks an important mathematical property
Even mathematicians get lazy and create new syntax and short cuts to express their ideas. Programming is ultimately a human UI. It's easy to see why automatic type coercion was once popular (and probably will be again, I can almost guarantee this).
Do you have some more context? I suspect somehow things are getting coerced to slices and then compared.
[0] https://github.com/rust-lang/rust/blob/e4c23daeb461ac02413eb...
(let [x “test” y “test”]
(= x y))
; returns true with both (let) and individual (def)
https://clojure.org/guides/equalityIt honestly makes me not want to open HN threads about JS as I know I will be met with a barrage of negative comments about something that I enjoy. I'm all for open discussion of the downsides of the JS ecosystem but that is rarely what these comments are.
> browser incompatibilities are still prevalent
It's true, browser difference are a pain to work with. But what is the alternative, to only support a single browser engine? Note that this has improved a lot in recent years. As long as you don't need to support IE11 or below then you shouldn't come across many issues. You can find browser support using caniuse.com or looking at MDN docs.
> even popular libraries are barely documented and you regularly have to wade through hundreds of wannabe tutorials on Medium/Hackernoon/...
I don't think that incomplete documentation is is exclusive to Javascript by any means. It is quite possible that the standard for packages and articles is lower due to Javascript having a lower entry level. I think we saw a similar thing with PHP.
> one compiler/transpiler, no, there are several...
I personally don't see a problem with this? Usually they have different goals, pros and cons. Do we think that it would be beneficial to not create competing solutions? For example would it be beneficial to only have React and not have Angular, Vue, Svelte? Agreed that multiple solutions can be confusing for new users and generally I would direct new developers to all-in-one solutions so they don't need to deal with these things.
> some things like imports might work in completely different ways
I'm not quite sure what is being referred to here, maybe the difference between commonjs and es imports? I personally haven't encountered any issues but they are completely different. I might be able to point someone in the right direction if they clarify.
Again I understand if you don't like having to deal with these things, but there are reasons for them that can't just be glossed over. Discussions are great! But I find it hard to have them when developers ignore the nuances and insist on approaching them from a negative angle.
Also what languages do you like less than JS? A lot of people think working with a certain tool is "as good as it's going to get" until they try something better.
I don't dislike any language in that sense, every language has pros and cons. Different tools for different jobs, some I enjoy more than others. But that wasn't the point.
This thread is about improving JavaScript tooling. It seems like a very appropriate place to discuss things you dislike about JavaScript.
> I don't dislike any language in that sense, every language has pros and cons. Different tools for different jobs, some I enjoy more than others.
The problem with JavaScript is that it wasn't designed for the job it's doing and (until recently) we really had no other options. We still don't have another language that is browser-native, unless you count Web Assembly.
So some of the JavaScript hatred is due to the fact that 100% of web developers have to use it whether they like it or not.
I dislike this overly positive attitude: responding to criticism of a language being worse than others by saying "every language has pros and cons" avoids addressing the criticisms and seems to imply that there are no bad languages.
It is possible to design a bad language for complex projects.
There are languages that treat javascript as a compilation target. Purescript, Elm, Closurescript, Rescript, Scalajs, etc. So if you really dislike javascript, you are still free to pick something else.
Performance-wise, sure. But the parent commenters were not complaining about performance; they were upset about javascript's syntax, or lack of type guarantees, or typecasting, and so on. Well, all of this can be taken care of by the compiler, if the developer dislikes javascript itself so much.
Using languages that don't come with the platform SDK, or aren't used to build the underlying platform, always add development costs with additional FFI, debugging tools, binding libraries,....
Why we have so many of the same thing that seemingly solves the same issues? Could it be because people have different needs and requirements that aren't already solved by these tools? Perhaps the tools over complicate things that could be simplified? From Grunt and Gulp, onto Webpack, Parcel and Rollup, and now Snowpack, ESBuild and WMR – Each solving a similar problem much differently from each other due to the new kind of applications and the problems that come with it. To provide a good user experience for a majority of people, there are a lot of things that has to be done to make that possible here and now. Browsers, unfortunately, don't update quick enough to provide the UX until the problem is big enough to warrant a built-in solution. That is how the web has been able to move forward; by peoples innovation in the space and the approaches they took to solve them.
It is reassuring that we have actually got the feature sets and interfaces correct, since we are now, at last, turning to making stuff really fast. If we had started with speed being the goal of tools, I'd wager they would have been nowhere near the standard they are today in those regards.
Wait, when did that happen?
Ironically, it's this principle that makes me look to non-Rust languages; I find that Rust's borrow checker forces us into faster but less flexible patterns up-front, and incurs a lot of refactoring friction later.
It's because of this that I'm interested in the PL space, and excited about upcoming languages like Lobster and Cone.
I wouldn't rewrite my project to some other language before I know how it is going to look like in the language. I had to be somewhat confident. If you find yourself frustrated by Rust's borrow checker, that tells me that you are not yet ready to port a project to Rust. You don't have the "Rust mindset" yet.
More to the point, in my many years of experience with Rust, I've found that if you're working on a stateless project, or a small project, or have a very clear picture up-front, you can know what data you will need to centralize and split ahead of time, and things will go smoothly. However, that's rarely the case in the parts of industry I've been in, where we need to prototype, refactor, and build out our programs constantly. In these cases, Rust is slower to work with compared to other languages, because the borrow checker makes our APIs brittle, causing refactors' blast radius to increase.
I'd be curious to hear if your architecture experience with large Rust projects might be different, I'm always open to more data points.
- Boa (JS engine in Rust) – https://github.com/boa-dev/boa
- RSLint (JS/TS linter in Rust) – https://github.com/rslint/rslint
- Node version manager in Rust – https://github.com/Schniz/fnm
If you know of any other popular ones, let me know. I'm keeping a list :)
They just put out an alpha release that makes it way more ergonomic to write Rust functions that interop with JS, too. There's a small example of it in the README: https://github.com/napi-rs/napi-rs#taste
NAPI isn't as well-known in the JS-to-Rust bindings world (Neon is the more well-known library, https://neon-bindings.com/) but it seems to be gaining steam.
It was mentioned in the article but swc as an alternative typescript compiler has really sped up builds.
If Rust becomes popular for JavaScript tooling, how long until those developers abandon JavaScript entirely? This isn't necessarily a problem, but it could lead to some, if you can't fix your own tools because you're not conversant in the language. More importantly, if the key toolmakers all switch to Rust and lose interest in JavaScript, the tool authors might lose touch with (or interest in) the problems of the JavaScript community. We all talk about dogfooding, and this is the opposite.
Rust seems to have this cult-like power. Rust developers are definitely drinking a lot of Kool-Aid. Maybe if all the JavaScript tools are written in Rust, we'll start seeing Rustscript in the browser.
Rust has tremendous popularity because it solves an enormous class of problems for system programmers and require very few compromises compared to any alternative.
The hype is real, but it is very unlikely that another language will compete for this space.
Rust doesn't really work well in the niches most impacted by fad-driven-development. Nobody is claiming you should do web dev in Rust nor consider it comparable to much better languages for that space.
The community is pretty exciting, new things are being written every day with the language, people are approaching it with optimism. Sure you can call it cult like and take the cynical route, I'm just going to be happy that I can write safe and performant code using a language with modern ergonomic features. I imagine this must have been what it was like in the early days of python and ruby.
Rust is to lazy memory allocation as static types are to lazy typing.
A lot of people are content with dynamic typing until they see the other side. These people claim types make you think more. Ultimately, they reduce the maintenance burden and get rid of an entire class of bugs.
The same can be said of GC tuning.
Rust is a game changer, and it certainly doesn't hurt that the tooling and language ergonomics are also the best in class. They hit a home run with all of the bases loaded with this one.
Memory allocation is painful in Go?
https://blog.discord.com/why-discord-is-switching-from-go-to...
> There are millions of Users in each cache. There are tens of millions of Read States in each cache. There are hundreds of thousands of cache updates per second.
This is something that is probably never going to be hit locally in the development toolchain. You can certainly prefer the Rust memory system to Go and have that be a valid reason to use Rust over Go for something like dev toolchains, but you're not going to hit scale problems like those mentioned in the article.
I think more engineers are becoming skeptical of optimizing compilers with that sort of implicit, potential "spooky action at a distance" where nonlocal code can cause performance regressions.
In Haskell, laziness and iterator fusion can do the same thing. Nonlocal code can cause local expressions to compile differently, resulting in - from an engineer's POV - nondeterministic performance, memory usage, GC pressure. "Space leaks" can also occur, again, due to nonlocal effects.
In JavaScript, the JIT can similarly cause local regressions due to nonlocal code. A single expression deep in a call stack mutating an object can result in it no longer fitting an optimized "shape", resulting in function deoptimization.
Just say no to spooky action at a distance in programming languages, in my opinion. It leads to tremendously difficult to debug regressions.
I thought heap allocations are only triggered by taking pointers, i.e. using reference semantics (including casting to interface and calling a method whose receiver is by-ref)? If I'm careful to only use variables by-value (for types that can afford it, i.e. excluding map/array), what else can trigger heap allocation?
package main
import "fmt"
func main() {
closure := make_closure()
fmt.Println("closure():", closure())
}
func make_closure() func() int {
x := 1
return func() int { return x }
}
This prints: $ go run main.go
closure(): 1
If x were allocated on the stack, it would get nuked after we returned from make_closure(). In Rust you could move x to the closure, but I think in this Go example x would be heap allocated, assuming the Go compiler doesn't notice it can inline all of this and avoid allocating. Maybe assume a more complex example with a struct that had to be computed via a function argument or something :)Because it's not the case with Rust or any compiled language? LLVM has shown regressions wich is what Rust uses to compile code.
2sec search on google: https://github.com/rust-lang/rust/issues/24194
I think there may be some edge cases (constant folding, dead code removal) of course, but a change to LLVM cannot cause the 3 sorts of changes I identified in Go, Haskell, and JavaScript.
Am I correct that redis does not offer a native API and so forces you to craft commands as strings? Just having to run snprintf 500k per second wastes a considerable amount of CPU. Combined with the normal overhead of communicating over a socket, using redis is going to be considerably slower than just keeping that memory in your own process. That's assuming the overhead of the redis internals is 0.
>The service we switched from Go to Rust is the “Read States” service. Its sole purpose is to keep track of which channels and messages you have read
>On cache key eviction, we commit your Read States to the database. We also schedule a database commit for 30 seconds in the future whenever a Read State is updated.
So it's a separate service whose only purpose is to store data in-memory with occasional commits to persisted DB, which sounded a lot like Redis. But of course, a special optimized service is always going to outperform a general purpose tool such as Redis.
They also replaced HashMaps with BTreeMaps, reduced the number of memory copies they were doing, etc. -- which has nothing to do with Go, but also contributed to a performance increase
It's not a library interface if you mean that - but that always applies for distributed systems.
* They incur the pain even when nothing needs doing. This is really terrible. If you spend ten minutes furiously reading data from a network device into a fixed RAM buffer, twiddling it, and writing it out again, in Rust (or C, C++ and various other explicit allocation languages) you neither allocated nor de-allocated anything, therefore you pay exactly zero for this work you didn't do. In Go you will incur the cost of the GC verifying that yup, everything is as it was, there's nothing to do, apparently five times.
* The pain is swallowed in lumps, you can't spread it out. So you must either size hardware for lump swallowing, even though as we saw above we don't even want to swallow any lumps, or accept poor performance each time a lump is swallowed. With explicit allocation you can choose to swallow bigger lumps (e.g. arena allocation) to reduce overheads elsewhere, but you decide on the size of lumps you want for your allocation.
But every large Go project I've worked on has eventually invested a lot of time into minimizing allocations, rewriting critical path sections to use pools, and various other techniques to improve performance by taking more control over memory allocation. Go's GC is very good, but it still has limitations.
Honestly it's not a bad tradeoff most of the time. Write code that works as quickly as possible, profile it as load scales, and apply further optimization as hot paths are identified. On the other hand, I've been working with Rust long enough that I can almost write the same thing in Rust as fast as I could in Go (Rust is inherently more verbose and requires more cognitive overhead). I've been writing prototypes in Rust more and more lately and haven't really been missing Go as much as I did when I first started with Rust.
- Greenspun's tenth rule
Joking aside, Java VM can be as fast as C++, not C, by using profiling and JIT optimization if tuned to a specific server and only measuring after running for a while. If you are really thinking about your allocators and not just calling malloc, nothing is faster. Half of this is due to less allocator calls and half is due to laying out the memory in a cache-friendly manner.
deno is too opinionated to absorb a significant number of node.js developers that just want to get stuff done.
Sure, there will be tools written in Rust (because it's the new sexy thing) just like there were tools written in Go (when it was the "new sexy thing"), but it's not going to take over the ecosystem any time soon.
> It's a modern replacement for languages like C++ or C with a focus on code safety and concise syntax.
Instead: "It's a replacement..."
> Babel: developers wanted to write modern JavaScript while supporting older browsers.
Instead: "developers want to write with new versions of Javascript..."
> Deno, created in 2018, is a simple, modern, and secure runtime for JavaScript and TypeScript that uses V8 and is built with Rust.
Instead: "Deno, created in 2018, is a runtime for JavaScript and TypeScript that uses V8 and is built with Rust, with a focus on Security."
> WebAssembly (WASM) is a portable low-level language that Rust can compile to. It runs in the browser, is interoperable with JavaScript, and is supported in all major modern browsers.
Instead: "all major browsers."
Dumb question - why do we still need compilers like Babel and SWC to compile our es6 (excluding TS) to...whatever version of js the compiler is targeting? Are browsers still so out of sync with each other that we still need to compile to es5? If yes, wouldn't it be more worthwhile for the front end community, including TC39 and every major browser engine developer (google, apple, mozilla, etc), to focus on the base implementation (engine) so they are no longer so out of sync? The most popular browser are based on open source engines anyway.
Don't get me wrong, I am sure there is a good reason for all this rust tooling - faster compilation does not hurt, but it seems inefficient to have an intermediate compiler (Babel / swc/ TS/ etc) that creates deployable code that will eventually be interpreted by the user's JS engine (V8 / webkit / gecko) anyway.
A standardized engine seems the way to go and it seems like we are going in that direction with only a handful of JS engines in use today.
Unfortunately we live in a diverse landscape of browsers and devices, many of which have not been updated in quite some time. Factors ranging from IT policy at older companies, to geographical limitations, may prevent many users from upgrading to the latest and greatest.
Some companies choose to cut their losses, and support only certain browsers - these can get away with less compilation and polyfills. Other companies may be targeting these specific segments (such as B2B), and can't get away with such a luxury.
And also anyone want to browse web using any browser they have at the time, it may be outdated.
Overall, browsers have gotten a lot better at implementing and supporting a common set of web APIs. There's still work to be done, but we're in a far better place than we were five years ago (in my opinion).
100% agree with your sentiment though.
The old browsers are on ES5.
- Still targeting legacy browsers like IE11
- Using React / JSX syntax
- Using TypeScript
- Using other brand-new JS syntax that hasn't trickled out to wider support yet
- Using custom JS transforms for libraries like `styled-components` (see this Next.js discussion thread for examples of the many different non-standard Babel transformations that people are using: https://github.com/vercel/next.js/discussions/30174 )
That said, the ideal target language version _is_ getting better. Jason Miller ( creator of Preact) has done a lot of research on both browser support for ES2017, as well as tooling to reverse-compile ES5-targeted published libraries upwards to ES2017 syntax again for improved bundle size:
I guess the WASM api is lacking a lot of features which would be required to make this work, but I don't see why it shouldn't be the goal.
The biggest downside is that even in http2 or http3, bundles can still perform better in terms of lower overall loading times, since individual modules you need to download the first one, and perform at least a bit of parsing to find the other modules statically imported before you can start downloading those, repeat.
With one exception though… cache invalidation of a single source file would not invalidate an entire bundle or chunk.
I've been a JS developer for almost 10 years. I'm convinced young hip developers are just addicted to tooling.
esbuild and babel/webpack do basically the same thing. esbuild can also target older versions of JavaScript (just not es5).
List of features in each version of JS: https://kangax.github.io/compat-table/es2016plus/ (also check the ES6 tab)
Young developers don’t know what they don’t know. If they don’t see editing the webpack configuration as part of their job, they’ll probably just never touch it.
And that means it’s your job to go fix it! Compiling down to es5 can have terrible performance implications for the resulting application - particularly if any of the bundled code touches typed arrays. There’s some free performance wins sitting on the table. If your coworkers are too junior, it falls to you to fix the build.
So keep going, you're on the right track.
There would still be benefit to webpack-like bundlers, if for no other reason then for performance/obfuscation reasons we would probably want the number of modules as seen by the broswer to be smaller than the number of modules that developers like to use for development purposes.
Many would still want minification for both performance and obfuscation reasons.
Many would still want to tree shake out any unused code from the libraries used (again for performance reasons).
Once one have all of that tooling, adding a babel like transpiler to the stack is not that big a deal.
https://rome.tools/blog/2021/09/21/rome-will-be-rewritten-in...
For one thing, Rust is slow to compile. I built a simple one-page app in rust/wasm to kick the tires, and it was much slower from a developer perspective than for instance a react/ts app. Even with hot reloading set up, it took noticeably longer for the rust app to refresh after hitting the save button.
Also rust is fairly demanding on the programmer. Right now there are an army of js programmers keeping the web running. To be perfectly honest, I don't think there is sufficient supply of programmers in the world with the aptitude to replace all those js programmers with rust programmers. Due to the sheer scale of the web, front-end programming has to be fairly easy for things to keep moving at the pace which they are.
I hope wasm does supplant js as the main deployment target for web development. But I think it will have to be a much simpler language than rust which is the one targeting wasm.
Rust & wasm don't replace JS, in my view. They're there to create good libraries & frameworks for the scripting languages to consume & use, at many times.
There will definitely be some Rust entering the scene, but I tend to think Rust & other wasms will not be the entire web app, but be used for engineering the better crafted, more re-usable bits.
Wasms success, imo, is ultimately gated on how well it's host-object bindings work. Wasm doesn't really yet play well with JS. Rust has a fairly unique edge right now in that Rust pioneered their own wasm<->js foreign interfacing, via wasm-bindgen, then generated a web-sys crate with all the web foreign objects already defined in it, allowing Rust far better inter-operation.
Because host-object binding/ interface types/ &c are still in-progress, there's much less ability to experiment with what pieces of the webapp make sense to keep in JS, and what pieces make sense to go engineer in wasm. We'll see more interesting blends, with more webdevs writing JS, but consuming/authoring against Wasm tools, as we start to emerge a real wasm ABI.
To my eye, JavaScript has three applications:
* A GUI-building language: A language and ecosystem we use to build UIs, where code runs on the end user's machine, served over the Web or as desktop applications using a compatible API (e.g. Electron).
* A scripting language: An approachable high-level C-like language.
* A general purpose programming language: A server-side or developer machine-side programming language for computational tasks like linking dependencies, transpiling code, type checking, orchestrating tasks.
At the first it's unbeatable, and the ergonomics and ecosystem are phenomenal. This is why it "won" as a language to write even desktop apps like VSCode and Discord.
At the second, performance doesn't matter anyway, so making JS capable of this just makes it approachable for folks who learned the language for the GUI-building purpose.
It's at the third application that the fundamental limitations of JavaScript---the programming language---really show. These are things like the lack of true multithreading (technically possible with significant limitations around shared memory and messaging and high overhead with Web Workers), lack of low-level primitives to fine-tune performance, and the ease with which authors can accidentally write extremely slow code. So much of this (TypeScript compilation, NPM package resolution/linking, Webpack bundling) in the modern Web ecosystem is regrettably still done in mostly JS.
I hope the JS community rallies around one general-purpose language to offload these tasks to as well as a uniform shim layer like Ruby's C extensions so we don't end up with a chaotic mishmash of different technologies. If nothing else, it would be nice to have a good excuse to write not-JS every once in a while!
I don't really think this is attributed to JS in any way besides it being the only browser language. Desktop apps use JS because they are browsers, not necessarily because JS was the best language option. An ecosystem has developed around it not because it's good, but because there is no other option for working in a browser.
Until somebody fixes this, I don't see Rust taking on any mainstream languages.
Maybe some day I'll write a Rust program that has a bug worth using a debugger on and I'll remember this.
Wow. I always thought Go was a language for depressed (or depressing? :)) devs ;) . I mean, it's boring _by design_. On the other hand Rust is really a cool language, with many things that are designed cleverly, and really enjoyable to use. Well, to me, at least, as it seems some people like boring more :)
"the rust programming language" has taken over "the c programming language" in the "c programming" best sellers mind you!
i am getting more and more curious about this language. i have avoided it for a long time because of the inconsistent syntax i have seen in the wild.
It still baffles me when i try to understand parts of it in isolation. As with all things it normalizes with exposure.
What do you mean?
I am hazy, not done as much Rust as I would like
I am interested in what the issues are people have had
My personal opinion is that all we can conclude today is that JavaScript is not the future of JavaScript infrastructure. However, I am somewhat unconvinced that Rust’s strengths are conclusively important enough to offset the added complexity in all use cases. In production where you might have cases where every cycle and byte counts and where a race condition or memory bug could come at a dire cost, Rust is an obvious winner. On a developer’s computer that is running mostly idle and running dev tools that are mostly embarrassingly parallel with little shared state, it’s just not so clear. Which is why I feel putting the Discord pull quote about their Rust migration underneath the testimony of evan regarding esbuild is a little bit misleading.
I am still very bullish on Rust, but when honeymoon periods end, the truth comes out, and in Rust my opinion is that the language is pretty complex, the build times need a lot of work, and the ecosystem has some pretty difficult to ignore weaknesses (I reasonably frequently run into packages that are incomplete, and the dependency trees in Rust projects seem to get as unwieldy as smaller JS/npm projects!)
Don’t get me wrong. Go and Zig, as two promising other languages, are obviously not competing with Rust directly. What Rust offers is fairly unique even for a memory safe language. Also, Go’s lack of sum types and pattern matching hits me harder than its verbose error handling or lack of generics. But many people, seeing the borrow checker in action, seem to conclude that it is the future, and that everything else is obsoleted by its existence. Disagree. I think all of these languages are formidable opponents and worthwhile improvements over older languages that people are migrating from. But the thing about zero cost abstractions is that they are a misnomer. They have zero cost at runtime. They have non-zero cost at compile time, they have non-zero costs on cognitive overhead, they have non-zero costs on language design… and once you acknowledge this, it’s only fair to recognize that there are cases where it’s not the trade-off you want.
Still, I hope to see more adoption of what I’ll call “next generation” programming languages. Be it Rust, Zig, Go, Pony, Nim… there really is a lot promising on the horizon, stuff that will be well worth the “RiiR” costs in the long-term. I have a feeling many of them will find a place and wind up complementing each other as options you can choose for differing tastes and goals. I am very interested to see which programming language ultimately wins for JS toolchains because it might tell us a lot about just how versatile Rust’s tradeoffs are or aren’t. For now, I am happy enough with esbuild, and looking out into the future to see what’s next.
Many other high levels languages might give you the performance you need, but JavaScript won’t, and not many languages are as nice to use as Rust. So if you have to do it in another language then it’s a good pick.
Yes, it's theoretically possible to write fast tools in JS, but somehow after all these years and millions/billions of dollars invested in the V8 JIT, they are all still slow enough that people will switch to newer tools, with fewer features, purely for the performance win. And these new tools end up faster with little developer time spent on profiling/optimization, because performant code is in the pit of success.
I also wouldn't think of Rust as a low-level language. It has plenty of high-level features like macros, typeclasses, iterators that are nicer than in JS, etc. Speaking as a developer, these make Rust much nicer/faster to use than other languages that lack these things.
As if your assembly-run CPU would be magically faster running three damn gigabytes of code in another language.
JS isn't the problem.
Babel is the problem. And every library using it, instead of using ES2020+ directly because every Browser supports it anyways.
NPM needs an ESM modules based header files system, and packages should be not binary, not uglified, but maintained by a standard of expectations what a library can and cannot do. Split up header files, namespaces for definitions, and expected types for all functions.
"Still using phantom? Sorry we block your package because it's outdated."
"Compiling to es5 commonjs with ie6 setting? Sorry, your package is outdated."
The ecosystem in JS has become a joke not because of the language, but because of the tooling. And now writing tooling in another language to replace that tooling will just end up in the exact same state all over again.
For the love of Rust, please don't fuck up rust crates the way the Babel fatigued ecosystem did. Don't go the micropackage way, it didn't work and it's time to reflect on that, and build up a standard library in a more centralized way.
Any AOT compiled language would produce the same performace results.