8 ms·
Supercharge Your Node.js with Rust
- rsgo1 5y agoSmall improvement: The call to unwrap() in fibonacci_api() can be replaced by `?` because JsResult is just a fancy std::result::Result
- skwee357 5y agoYou are right. I'm a messy person when it comes to `?` and `.unwrap()`
- vaughan 5y agoNAPI-RS is another option to Neon. It’s faster and has a new feature in beta that automatically does the type wrapping for you.
- skwee357 5y agoThanks for the suggestion! NAPI-RS does look cleaner than Neon. I wonder what's the difference though. Do you know maybe? It looks like NAPI-RS Docs does not list any meaningful differences.
- dceddia 5y agoI’ve been using NAPI-RS and I like it a lot so far. The feature that caused me to switch was callbacks - specifically, I wanted to pass a JS callback to Rust, and have Rust call it repeatedly. I couldn’t figure out how to do that with Neon, but Napi has support and docs for it. One difference is that NAPI-RS uses Node’s N-API for calling Node, and Neon has a mix of N-API and v8 backends. I’m not sure if this is the main reason behind the speed difference or not.
- Ginden 5y ago> And yet, I rarely hear people suggest or even evaluate the solution of embedding a native module that most of the times will be faster. Because there's rarely a real benefit to this approach. I have yet to found use case where C/C++/Rust library is useful AND spawning process to do heavy work is not a viable option AND JS-only library won't work. I can think basically only about communication with external resource like database.
- isabellat 5y agoWe're doing exactly this in our language libraries for Tangram. Our core machine learning code is written in Rust and we use a native add-on so people can make predictions directly from their javascript apps. In Python, this is incredibly common: NumPy, LightGBM, XGBoost are written in C/C++ and exposed to Python.
- eyelidlessness 5y agoA really common use case that comes to mind immediately: parsing and AST transforms. Quite common in build tooling, quite noticeable performance difference as evidenced by SWC. (ESBuild doesn’t expose its AST, but it’s also quite a lot faster than comparable plain JS at what it does expose in its JS interface).
- Ginden 5y agoI wrote about use case where "spawning process to do heavy work is not a viable option". ESBuild DOES spawn process to do heavy work. https://github.com/evanw/esbuild/blob/11d7eacd491c94d2aa23cd7d48ffd9195f26c108/lib/npm/node.ts https://github.com/evanw/esbuild/blob/11d7eacd491c94d2aa23cd...
- eyelidlessness 5y agoYou’re correct. I didn’t cite ESBuild as a use case, I mentioned it to give credit where it was due.
- trinovantes 5y agoThe performance difference between webpack and esbuild is like night and day
- wruza 5y agoI can think basically only about communication with external resource like database. And when it is a database, all the benefits of a compiled language turn into just a fancy no-brainer wrapper which still sucks because of “impedance mismatch”. It would be nice if that was true jit-integrated rust or at least C ffi, which one could call directly from js. But I don’t think that v8 will get such capability in observable future.
- dherman 5y agoNeon maintainer here, happy to answer any questions folks might have! It's a pretty exciting time for Neon. We're nearly feature-complete for a 1.0 release, which will come with a bunch of benefits and should help us build momentum for future improvements: * No more legacy backend -- just one simple and clean way to use Neon, fully audited for safety. * Strong ABI and API stability guarantees. * Convenient APIs for general-purpose multithreading and creating custom async Node events. * Ergonomic and modern use of JS promises, which interact beautifully with async Rust code. Some of the things I'm looking forward to exploring post-1.0 is even more ergonomics and performance improvements.
- skwee357 5y agoI just wanted to say: Thank you! Neon is great!
- gravypod 5y agoIs there a way to generate automatic bindings for rust/js code from the AST of the language and a list of definitions to specify? I'm imaging how powerful a Bazel ruleset for this could be. Something like js_rust_library(... defs = ["someFunction"] ...)
- dherman 5y agoThat's a cool idea! The closest thing today is probably neon-serde, a cool community library that lets you generate bindings from lightweight Rust annotations: https://docs.rs/neon-serde2/0.8.0/neon_serde2/ Another thing I'd love to explore is using TypeScript declarations (e.g. from a .d.ts file) to auto-generate bindings. If you're interested in playing with any of these ideas feel free to hop onto our community Slack and chat!
- ukulele 5y agoThank you for building it! I haven't kicked the tires yet, but as a node developer, this feels like the future: we can move fast with node when it makes sense, and get rust level performance when we need to. Best of both worlds!
- 5y ago
- trinovantes 5y ago> handle.value(&mut cx) as i32 What happens when the user in JS land passes in an incorrect data type? Does it segfault? Does it truncate the first 32 bits?
- skwee357 5y agoAs @brundolf said above me, it will return Error because I explicitly downcast it to `JsNumber` and unwrap the result. So from JS side you'll get an error. Obviously, you should handle such cases properly.
- brundolf 5y agoIf they don't pass a number at all, looks like cx.argument() will return a Result::Err (which in the example will panic because of the unwrap(), but can instead be bubbled up as another commenter pointed out here: https://news.ycombinator.com/item?id=28977697 https://news.ycombinator.com/item?id=28977697) JsNumber::value() then returns an f64 to encapsulate all possible JS numbers, and `as i32` is just casting that float into an int. The exact behavior for this cast is that a) any fractional component will be dropped, and b) if the number is larger than the destination type, the destination's maximum value will be used. Both of these behaviors could of course be controlled by adding logic, like an explicit call to .round()