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

Proposal: add JavaScript support via OXC #106

Open
shahryarjb opened this issue Oct 21, 2024 · 10 comments
Open

Proposal: add JavaScript support via OXC #106

shahryarjb opened this issue Oct 21, 2024 · 10 comments
Labels
enhancement New feature or request

Comments

@shahryarjb
Copy link

Requirement

One feature that could significantly enhance Igniter's support for all basic requirements in Phoenix is a robust JavaScript parser or manipulator.
Developing this from scratch would be a large-scale project, requiring considerable time and effort.

Therefore, I suggest considering the Oxc project, which is implemented in Rust, as a potential solution.


Where we can use it:

Imagine you want to create a Phoenix component that requires a phx-hook. You would need to modify the app.js file to inject the entire JavaScript file into the Hook object, or alternatively, create a separate JavaScript file, import it into app.js, and then inject it into the hook.

Currently, all of this is done manually in Elixir projects, which involves a lot of documentation and a complex process. This approach is not ideal and can discourage users from using it.

For example, take a look at this object that I injected using the JavaScript spread operator.

hooks: { ...Hooks, CopyMixInstallationHook }

No I want to add GetUserText object.

# This code is from ChatGPT, so it is not totally valid code
let ast = parser.parse().expect("Failed to parse the JS code");
for node in ast.body {
    if let Some(object_literal) = node.as_object_literal() {
        for property in object_literal.properties {
            if property.key == "hooks" {
                property.value.push("GetUserText");
            }
        }
    }
}

Thank you in advance

Refs

@shahryarjb shahryarjb added the enhancement New feature or request label Oct 21, 2024
@TwistingTwists
Copy link

https://github.com/TwistingTwists/igniter_js

@shahryarjb
Copy link
Author

shahryarjb commented Oct 22, 2024

https://github.com/TwistingTwists/igniter_js

I think if it comes into ash-project org and collaborate, would be good; or even on igniter as core optional installing

@zachdaniel
Copy link
Contributor

Agreed :) Still in the early stages of discovery.

@jimsynz
Copy link

jimsynz commented Oct 22, 2024

I'm happy to work on a Rustler integration if needed.

@zachdaniel
Copy link
Contributor

There is some discussion in the igniter discord channel on the rustler side of things. Would be a wonderful to have more eyes and hands on it

@TwistingTwists
Copy link

@jimsynz : Currently I am expanding on ideas on the best way forward to integrate js parser and ast manipulator from elixir.

Here is one approach I have decided to take (unless there are unknown unknowns):
the oxc crate has oxc_parser for parsing js to ast and oxc_ast for ast manipulation.
If we can bind to oxc_ast from elixir, we can get a well maintained + production ready js ast manipulator.

I imagine writing one JS AST manipulator in elixir would be possible, but keeping it upto date would be a hassle.


So, the plan is to have ast in rust. Reference that AST struct from elixir. manipulate that ast in js using oxc_ast and give the bindings from elixir.


This is the 4 step plan (rough direction) as suggested by @zachdaniel

  1. Create a custom Rewrite.Source for js that behaves like the Ex Rewrite source behaves.

  2. Create a Zipper data structure for traversing and manipulating AST (this is complicated, I barely understand the Sourceror.Zipper 😆 )

  3. Start the work of creating a library of functions to manipulate the zipper, which would be namespaced under something like Igniter.Js.Code.

  4. figure out how we can make this available w/o requiring a dependency on rust. There are tools for doing prebuilt binaries, or we'd make it an optional thing that users have to opt into if they want to get js patches in addition to elixir patches.

@TwistingTwists
Copy link

TwistingTwists commented Oct 23, 2024

Here is what I found about integration rust Struct and elixir

  1. create a resource : basically, use Arc<Mutex>

  2. expose an nif to take the reference to that resource and do something.

@TwistingTwists
Copy link

Here is what I found about integration rust Struct and elixir

  1. create a resource : basically, use Arc<Mutex>
  2. expose an nif to take the reference to that resource and do something.

same pattern found here as well:

  1. create struct using Mutex. Hide it behind Arc
  2. Bonus - you can even nest the references to struct if you do Arc<Mutex>

@TwistingTwists
Copy link

Here are more code references:

  1. create a new resource and return that
  2. take resource in 1 as ref do some ops on it.

@zachdaniel
Copy link
Contributor

What is the general solution to #4 above? If we're going to invest a lot of time and energy into this via rustler, we need to have confidence that we can ship this to effectively any platform someone is developing on. The nice thing about pure elixir solutions is that we know they have elixir installed at a minimum 🤣

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants