Plugin module loading

This commit is contained in:
Gregory Schier
2023-10-29 20:50:23 -07:00
parent 851082be9d
commit 451ffad24a
7 changed files with 108 additions and 48 deletions

View File

@@ -1 +0,0 @@
sayHello('Plugin');

View File

@@ -0,0 +1,3 @@
export function hello() {
sayHello('Plugin');
}

View File

@@ -0,0 +1,5 @@
import { hello } from './hello.js';
export function entrypoint() {
hello();
}

View File

@@ -32,7 +32,7 @@ use window_ext::TrafficLightWindowExt;
mod models;
mod render;
mod window_ext;
mod plugins;
mod plugin;
#[derive(serde::Serialize)]
pub struct CustomResponse {
@@ -689,7 +689,7 @@ fn main() {
let w = create_window(app_handle, None);
w.restore_state(StateFlags::all())
.expect("Failed to restore window state");
plugins::test_plugins(&app_handle);
plugin::test_plugins(&app_handle);
}
// ExitRequested { api, .. } => {

97
src-tauri/src/plugin.rs Normal file
View File

@@ -0,0 +1,97 @@
use boa_engine::{
js_string,
module::{ModuleLoader, SimpleModuleLoader},
property::Attribute,
Context, JsArgs, JsNativeError, JsValue, Module, NativeFunction, Source,
};
use boa_runtime::Console;
use tauri::AppHandle;
pub fn test_plugins(app_handle: &AppHandle) {
let plugin_dir = app_handle
.path_resolver()
.resolve_resource("plugins/hello-world")
.expect("failed to resolve plugin directory resource");
let plugin_entry_file = app_handle
.path_resolver()
.resolve_resource("plugins/hello-world/index.js")
.expect("failed to resolve plugin entry point resource");
// Module loader for the specific plugin
let loader = &SimpleModuleLoader::new(plugin_dir).expect("failed to create module loader");
let dyn_loader: &dyn ModuleLoader = loader;
let context = &mut Context::builder()
.module_loader(dyn_loader)
.build()
.expect("failed to create context");
add_runtime(context);
add_globals(context);
let source = Source::from_filepath(&plugin_entry_file).expect("Error opening file");
// Can also pass a `Some(realm)` if you need to execute the module in another realm.
let module = Module::parse(source, None, context).expect("failed to parse module");
// Insert parsed entrypoint into the module loader
// TODO: Is this needed if loaded from file already?
loader.insert(plugin_entry_file, module.clone());
let _promise_result = module
.load_link_evaluate(context)
.expect("failed to evaluate module");
// Very important to push forward the job queue after queueing promises.
context.run_jobs();
// // Checking if the final promise didn't return an error.
// match promise_result.state() {
// PromiseState::Pending => return Err("module didn't execute!".into()),
// PromiseState::Fulfilled(v) => {
// assert_eq!(v, JsValue::undefined())
// }
// PromiseState::Rejected(err) => {
// return Err(JsError::from_opaque(err).try_native(context)?.into())
// }
// }
let namespace = module.namespace(context);
let entrypoint_fn = namespace
.get(js_string!("entrypoint"), context)
.expect("failed to get entrypoint")
.as_callable()
.cloned()
.ok_or_else(|| JsNativeError::typ().with_message("export wasn't a function!"))
.expect("Failed to get entrypoint");
// Actually call the entrypoint function
let _result = entrypoint_fn
.call(&JsValue::undefined(), &[], context)
.expect("Failed to call entrypoint");
}
fn add_runtime(context: &mut Context<'_>) {
let console = Console::init(context);
context
.register_global_property(js_string!(Console::NAME), console, Attribute::all())
.expect("the console builtin shouldn't exist");
}
fn add_globals(context: &mut Context<'_>) {
context
.register_global_builtin_callable(
"sayHello",
1,
NativeFunction::from_fn_ptr(|_, args, context| {
let value: String = args
.get_or_undefined(0)
.try_js_into(context)
.expect("failed to convert arg");
println!("Hello {}!", value);
Ok(value.into())
}),
)
.expect("failed to register global");
}

View File

@@ -1,44 +0,0 @@
use boa_engine::{
js_string, property::Attribute, Context, JsArgs, NativeFunction, Source,
};
use boa_runtime::Console;
use tauri::AppHandle;
pub fn test_plugins(app_handle: &AppHandle) {
let file = app_handle
.path_resolver()
.resolve_resource("plugins/hello-world.js")
.expect("failed to resolve resource");
let src = Source::from_filepath(&file).expect("Error opening file");
// Instantiate the execution context
let mut context = Context::default();
add_runtime(&mut context);
// Add globals
context
.register_global_builtin_callable(
"sayHello",
1,
NativeFunction::from_fn_ptr(|_, args, context| {
let value: String = args
.get_or_undefined(0)
.try_js_into(context)
.expect("failed to convert arg");
println!("Hello {}!", value);
Ok(value.into())
}),
)
.expect("failed to register global");
context.eval(src).expect("failed to execute script");
}
fn add_runtime(context: &mut Context<'_>) {
let console = Console::init(context);
context
.register_global_property(js_string!(Console::NAME), console, Attribute::all())
.expect("the console builtin shouldn't exist");
}

View File

@@ -165,7 +165,7 @@ export const Sidebar = memo(function Sidebar({ className }: Props) {
tabIndex={hidden ? -1 : 0}
className={classNames(
className,
'h-full pb-3 overflow-y-scroll overflow-x-visible pt-2',
'h-full pb-3 overflow-y-scroll overflow-x-visible hide-scrollbars pt-2',
)}
>
<SidebarItems