Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Bun as an available runtime #127

Merged
merged 2 commits into from Sep 11, 2023
Merged

Add Bun as an available runtime #127

merged 2 commits into from Sep 11, 2023

Conversation

terracatta
Copy link
Contributor

@terracatta terracatta commented Sep 10, 2023

Resolves #119

This PR adds a new JS Runtime called Bun as a new supported external Runtime.

What is Bun?

Bun is a very very fast JS runtime that's meant to be mostly compatible with NodeJS. While not quite a full-drop-in replacement, it often performs significantly faster running equivalent code. For example check out the the test suite

Node

======================================================================================================================================
Running test:node
======================================================================================================================================
Finished in 15.048948s, 13.2900 runs/s, 16.9447 assertions/s.

Bun

======================================================================================================================================
Running test:bun
======================================================================================================================================

Finished in 9.078924s, 22.0290 runs/s, 26.7653 assertions/s.

Why Teach This Dog a New Trick?

It's a good question. With the recent announcement that Rails 8 will be ditching sprockets in favor of propshaft most Rails apps will not really have a need for execJS, so why invest time in supporting another runtime?

Well even though I already am a production propshaft user, I actually have a lot of uses for ExecJS and want to eventually be in a place where I don't have to ship the node runtime to my app.

Some examples of how I use ExecJS in my app

Validating SQLite

Back in the day, Codeschool wrote a really great SQLiite parser in JS. There isn't anything as good in ruby. With the power of ExecJS I could build a simple ~150 line wrapper library that feels as good and responsive as a native Gem.

[1] pry(main)> query = SQLiteParser.parse("SELECT foo FROM bar;")
=> #<SQLiteParser::ParsedQuery:0x00000001451d0330
 @ast=
  {"type"=>"statement",
   "variant"=>"list",
   "statement"=>
    [{"type"=>"statement",
      "variant"=>"select",
      "result"=>[{"type"=>"identifier", "variant"=>"column", "name"=>"foo"}],
      "from"=>{"type"=>"identifier", "variant"=>"table", "name"=>"bar"}}]},
 @query="SELECT foo FROM bar;">
[2] pry(main)> query.tables
=> [#<SQLiteParser::TableInfo:0x0000000148230ca0 @alias_name=nil, @columns=[], @name="bar", @variant="table">]
[3] pry(main)> query.columns
=> [#<SQLiteParser::ColumnInfo:0x0000000148230c50 @alias_name=nil, @name="foo", @selector="foo", @table="">]

Scoring Passwords

A few years ago Dropbox created a great JS library for validating password quality called [zxcvbn](https://github.com/dropbox/zxcvbn). While there are great ruby implementations of zxcvbn in practice we want to always make sure the warnings we serve to the user in the client-side are the exact same errors we would get on the server-side through an AR validator. The ruby implementations always fell short of that, so simply writing a wrapper with ExecJS for the same lib got the job done easily.

[0] pry(main)> Zxcvbn.test("foo")
=> #<OpenStruct password="foo", guesses=1001, guesses_log10=3.0004340774793183, sequence=[{"pattern"=>"bruteforce", "token"=>"foo", "i"=>0, "j"=>2, "guesses"=>1000, "guesses_log10"=>2.9999999999999996}], calc_time=1, crack_times_seconds={"online_throttling_100_per_hour"=>36036, "online_no_throttling_10_per_second"=>100.1, "offline_slow_hashing_1e4_per_second"=>0.1001, "offline_fast_hashing_1e10_per_second"=>1.001e-07}, crack_times_display={"online_throttling_100_per_hour"=>"10 hours", "online_no_throttling_10_per_second"=>"2 minutes", "offline_slow_hashing_1e4_per_second"=>"less than a second", "offline_fast_hashing_1e10_per_second"=>"less than a second"}, score=0, feedback={"warning"=>"", "suggestions"=>["Add another word or two. Uncommon words are better."]}>

Here is where we use it in an AR validator

if value.length <= ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED
  if Zxcvbn.test(value, record.additional_password_dictionaries).score < 3
    record.errors.add(attribute, 'is too easy to guess')
  end
end

In conclusion, ExecJS is a great way for me to plumb high-value functionality from the JS ecosystem with very little effort. Under that premise I think it's worthy of getting it in line with what I believe will eventually become most people's default runtime if a few years.

Notable Items

  • By default Bun runs everything in strict mode, currently the only way to force it to run things in sloppy mode is to use code that would only normally be found in a commonjs file like exports.abc = function(){}.

  • Bun has an implementation difference where in sloppy mode, you cannot delete the timing functions from the this object as they are set to configurable: false. I've filed a bug for this and until it is fixed (if it ever is) we will need to skip the associated test.

  • Bun outputs things a bit differently when you throw an exception during eval and I had to change some tests that had the assumption that the first line of a trace would include a reference to execjs.

  • I had to update the uglify.js fixture to bring it in line with the latest es5 compatibility shim. I sourced the latest and greatest from here.

@Jarred-Sumner
Copy link

A lot of Bun is inspired by Ruby on Rails, so as the creator of Bun this is really cool for me to see

re: deleting setTimeout, we will make it configurable: true

@byroot byroot merged commit 71fa935 into rails:master Sep 11, 2023
@byroot
Copy link
Member

byroot commented Sep 11, 2023

2.9.0 is out.

@terracatta terracatta deleted the jem_add_bun branch September 11, 2023 21:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

bun.sh as runtime
3 participants