DelSkayn / rquickjs

High level bindings to the quickjs javascript engine
MIT License
434 stars 59 forks source link

How to return the compiled module? #261

Open Sakapoi opened 4 months ago

Sakapoi commented 4 months ago

Is it possible to return the Module from a function to use it later for getting values of JS objects or calling JS functions? I am creating the module from Context with this code:

ctx.with(|ctx| {
    let module = ctx.clone().compile(file_name, content).unwrap();
})

But I can't return the module value because it does not live long enough. Are there any other ways to compile the JS code once and then use the compiled module to get the values of JS objects or call JS functions?

Thanks for the reply.

zeozeozeo commented 3 months ago

did you resolve this? I'm also wondering how to get a module from the context:

use crate::{Error, Result};
use rquickjs::{Context, Runtime};

fn init_runtime() -> Runtime {
    let rt = Runtime::new().expect("failed to create QuickJS runtime");

    let ctx = Context::full(&rt).unwrap();
    ctx.with(|ctx| {
        let module = ctx.clone().compile("mathjax", crate::MATHJAX_JS).unwrap();
    });
    rt
}

pub(crate) fn convert_to_svg_inner(latex: impl AsRef<str>, display: bool) -> Result<String> {
    thread_local! {
        static RUNTIME: Runtime = init_runtime();
    }

    RUNTIME.with(|rt| {
        let ctx = Context::full(&rt).unwrap();
        ctx.with(|ctx| {
            // how to get the "mathjax" module from here?
        });
    });

    Ok(String::new())
}
zeozeozeo commented 3 months ago

something like this kinda works, but I get a GC error now:

default: Persistent { rt: 0x4c0bf0, value: Function(Object(Constructor(0x10a2e70))) }

Assertion failed: list_empty(&rt->gc_obj_list), file <build directory>\out\quickjs.c, line 1989
use crate::Result;
use rquickjs::{Context, Function, Persistent, Runtime};

fn init_runtime() -> (Runtime, Persistent<Function<'static>>) {
    let rt = Runtime::new().expect("failed to create QuickJS runtime");

    let ctx = Context::full(&rt).unwrap();
    let default = ctx.with(|ctx| {
        let module = ctx.clone().compile("mathjax", crate::MATHJAX_JS).unwrap();
        Persistent::save(&ctx, module.get::<_, Function>("default").unwrap())
    });
    (rt, default)
}

pub(crate) fn convert_to_svg_inner(latex: impl AsRef<str>, display: bool) -> Result<String> {
    thread_local! {
        static RUNTIME: (Runtime, Persistent<Function<'static>>) = init_runtime();
    }

    RUNTIME.with(|(rt, default)| {
        let ctx = Context::full(&rt).unwrap();
        ctx.with(|ctx| {
            println!("default: {:?}", default);
        });
    });

    Ok(String::new())
}
DelSkayn commented 2 months ago

I will make sure that modules implement Outlive in the next release so that you can use them with Persistent.

Regarding the panic: You need to make sure that the value in persistent is dropped before the runtime is dropped. I believe that in a tuple the order of dropping is not defined so I might drop after the runtime is dropped. It is probably best to manually implement drop for a struct containing the persistent to ensure it is dropped in the correct order.