Open sunng87 opened 6 years ago
First things I saw that block this process is this issue from same-file
, a dependency used by walkdir
: https://github.com/BurntSushi/same-file/issues/42
Yes, this is known and I have a feature no_dir_source
that disable walkdir
Ha nice ๐ Sorry then
Never mind. By the way, if you are interested in a WebAssembly/JavaScript API for handlebars, feel free to discuss here. Things I have been thinking about:
Handlebars
document
implement for handlebars Output
APIIn recent days I have tried to wrap register_helper
using WASM. I have found two apis Function::new_no_args
and Function::from
in js-sys
package. It is mostly like javascript eval function, so we can save javascript function template and call it like eval
when calling rust helper. ๐ค
Here is the code:
use handlebars::{
Context, Handlebars as Registry, Helper, HelperDef, HelperResult, Output, RenderContext,
RenderError,
};
use js_sys::Function;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub struct HelperOptions {
template_ctx: JsValue,
inverse_ctx: JsValue,
}
#[allow(clippy::new_without_default)]
#[wasm_bindgen]
impl HelperOptions {
pub fn new() -> Self {
HelperOptions {
template_ctx: JsValue::undefined(),
inverse_ctx: JsValue::undefined(),
}
}
pub fn template(&mut self, ctx: JsValue) -> String {
self.template_ctx = ctx;
"$$TEMPLATE$$".to_string()
}
pub fn inverse(&mut self, ctx: JsValue) -> String {
self.inverse_ctx = ctx;
"$$INVERSE$$".to_string()
}
}
pub struct JsHelper {
pub js_fn_tpl: String,
}
impl HelperDef for JsHelper {
fn call<'reg: 'rc, 'rc>(
&self,
h: &Helper<'reg, 'rc>,
_: &'reg Registry<'reg>,
_: &'rc Context,
_: &mut RenderContext<'reg, 'rc>,
out: &mut dyn Output,
) -> HelperResult {
// Change function template to actual js function
let js_fn = Function::new_no_args(&self.js_fn_tpl);
let js_helper = Function::from(js_fn.call0(&JsValue::null()).unwrap());
let value = h
.param(0)
.ok_or_else(|| RenderError::new("Param not found in js helper"))
.unwrap();
let data = JsValue::from_serde(value.value()).unwrap();
let options = HelperOptions::new();
let result = js_helper
.call2(&JsValue::null(), &data, &options.into())
.unwrap();
let result = result.as_string().unwrap();
out.write(result.as_str())?;
Ok(())
}
}
And we can hack the js callback param options
like the struct HelperOptions
. When calling the fn
and inverse
function, tag it in return string and save the call info. Parse the result string with the call info in rust after js_helper
call finish.
๐ Not sure if it is the "best practices" or just a โtrickโ. Do y'all have a suggested workaround for this? (repo here)
Perhaps we can use HelperOptions
to hold enough information(render_context
, registry
and etc) and make template()
and inverse()
call that actually renders the template with that information.
๐ค Ah,ย I have tried but it does not work, because the wasm_bindgen
cannot have lifetime parameters.
Maybe we can use a static to hold that information, but for me it is another complicated workaround. Is it possible to ask you to provide more details about it?
I see. The data exchange between js and webassembly still requires some hack. I would prefer some result string/code for template()
and inverse()
over static holder, since it's more predictable and I tried best to avoid global state in handlebars.
Yep, if you have plans to add this feature, let me know if you need a hand.
Thank you! This feature is welcomed. Do you have a full example of your current usage of this library via wasm and javascript? I'm just wondering the scenario of defining helpers via javascript.
Not yet. I was using handlebars.js and doing some surveys about other more efficient template engines.
But I think the first step is to do some performance test for the js_helper
, because the data exchange cost here is a black box. But I need to start doing this after 4 days and will comment here again if any questions arise.
We are also considering using this library as a (wasm) replacement for handlebars.js, as handlebars.js requires unsafe-eval and therefore will not be possible to use in MV3 extensions at least on firefox. But we need to have as-close-as-possible support for existing users and all their handlebars scripts, so cannot easily drop in another library. This would require being able to use our existing JS helpers, or reimplementing all of those in Rust, which might be difficult/impossible.
Finally we have (wasm-bindgen)[https://github.com/alexcrichton/wasm-bindgen] to expose Rust struct to JavaScript, so we should be able to create
Handlebars
instance from JavaScript, and call any API from it.This has made it possible to create a JavaScript interface for handlebars-rust. The next step will be allowing JavaScript implemented helpers and directives being registered in handlebars-rust.