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 --target electron-renderer (for generating electron preloads) #1928

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 52 additions & 8 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ impl<'a> Context<'a> {
}
}
OutputMode::Bundler { .. }
| OutputMode::ElectronRenderer
| OutputMode::Node {
experimental_modules: true,
}
Expand Down Expand Up @@ -167,7 +168,10 @@ impl<'a> Context<'a> {
Ok(())
}

pub fn finalize(&mut self, module_name: &str) -> Result<(String, String), Error> {
pub fn finalize(
&mut self,
module_name: &str,
) -> Result<(String, String, Option<String>), Error> {
// Finalize all bindings for JS classes. This is where we'll generate JS
// glue for all classes as well as finish up a few final imports like
// `__wrap` and such.
Expand All @@ -194,9 +198,10 @@ impl<'a> Context<'a> {
&mut self,
module_name: &str,
needs_manual_start: bool,
) -> Result<(String, String), Error> {
) -> Result<(String, String, Option<String>), Error> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This return type is getting unfortunately pretty unwieldy, could this be updated to a named structure with documented fields?

let mut ts = self.typescript.clone();
let mut js = String::new();
let mut preloads = String::new();
if self.config.mode.no_modules() {
js.push_str("(function() {\n");
}
Expand All @@ -205,7 +210,8 @@ impl<'a> Context<'a> {
// import the wasm file in one way or another.
let mut init = (String::new(), String::new());
let mut footer = String::new();
let mut imports = self.js_import_header()?;
let mut imports = String::new();
self.js_import_header(&mut imports, &mut preloads)?;
match &self.config.mode {
// In `--target no-modules` mode we need to both expose a name on
// the global object as well as generate our own custom start
Expand Down Expand Up @@ -272,7 +278,7 @@ impl<'a> Context<'a> {
// browsers don't support natively importing wasm right now so we
// expose the same initialization function as `--target no-modules`
// as the default export of the module.
OutputMode::Web => {
OutputMode::ElectronRenderer | OutputMode::Web => {
self.imports_post.push_str("let wasm;\n");
init = self.gen_init(needs_manual_start, Some(&mut imports))?;
footer.push_str("export default init;\n");
Expand Down Expand Up @@ -310,11 +316,31 @@ impl<'a> Context<'a> {
js = js.replace("\n\n\n", "\n\n");
}

Ok((js, ts))
let preloads = if self.config.mode.electron_renderer() {
preloads.push_str("\nprocess.once('loaded', () => {\n");
for (_module, items) in crate::sorted_iter(&self.js_imports) {
for (_i, (item, rename)) in items.iter().enumerate() {
let mut name: &str = item;
if let Some(other) = rename {
name = other;
}
preloads.push_str(" global.");
preloads.push_str(name);
preloads.push_str(" = ");
preloads.push_str(name);
preloads.push_str(";\n");
}
}
preloads.push_str("});");
Some(preloads)
} else {
None
};

Ok((js, ts, preloads))
}

fn js_import_header(&self) -> Result<String, Error> {
let mut imports = String::new();
fn js_import_header(&self, imports: &mut String, preloads: &mut String) -> Result<(), Error> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of taking two out-parameters could this return a structure with named fields that document the meaning of each field?

match &self.config.mode {
OutputMode::NoModules { .. } => {
for (module, _items) in self.js_imports.iter() {
Expand Down Expand Up @@ -368,8 +394,26 @@ impl<'a> Context<'a> {
imports.push_str("';\n");
}
}
OutputMode::ElectronRenderer => {
for (module, items) in crate::sorted_iter(&self.js_imports) {
preloads.push_str("const { ");
for (i, (item, rename)) in items.iter().enumerate() {
if i > 0 {
preloads.push_str(", ");
}
preloads.push_str(item);
if let Some(other) = rename {
preloads.push_str(": ");
preloads.push_str(other)
}
}
preloads.push_str(" } = require(String.raw`");
preloads.push_str(module);
preloads.push_str("`);\n");
}
}
}
Ok(imports)
Ok(())
}

fn ts_for_init_fn(has_memory: bool, has_module_or_path_optional: bool) -> String {
Expand Down
25 changes: 24 additions & 1 deletion crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct JsGenerated {
mode: OutputMode,
js: String,
ts: String,
preloads: Option<String>,
snippets: HashMap<String, Vec<String>>,
local_modules: HashMap<String, String>,
npm_dependencies: HashMap<String, (PathBuf, String)>,
Expand All @@ -67,6 +68,7 @@ struct JsGenerated {
#[derive(Clone)]
enum OutputMode {
Bundler { browser_only: bool },
ElectronRenderer,
Web,
NoModules { global: String },
Node { experimental_modules: bool },
Expand Down Expand Up @@ -182,6 +184,13 @@ impl Bindgen {
Ok(self)
}

pub fn electron_renderer(&mut self, web: bool) -> Result<&mut Bindgen, Error> {
if web {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable "web" here probably wants a different name

self.switch_mode(OutputMode::ElectronRenderer, "--target electron-renderer")?;
}
Ok(self)
}

pub fn no_modules(&mut self, no_modules: bool) -> Result<&mut Bindgen, Error> {
if no_modules {
self.switch_mode(
Expand Down Expand Up @@ -412,7 +421,7 @@ impl Bindgen {
.unwrap();
let mut cx = js::Context::new(&mut module, self, &adapters, &aux)?;
cx.generate()?;
let (js, ts) = cx.finalize(stem)?;
let (js, ts, preloads) = cx.finalize(stem)?;
Generated::Js(JsGenerated {
snippets: aux.snippets.clone(),
local_modules: aux.local_modules.clone(),
Expand All @@ -421,6 +430,7 @@ impl Bindgen {
npm_dependencies: cx.npm_dependencies.clone(),
js,
ts,
preloads,
})
};

Expand Down Expand Up @@ -558,6 +568,13 @@ impl OutputMode {
_ => false,
}
}

fn electron_renderer(&self) -> bool {
match self {
OutputMode::ElectronRenderer => true,
_ => false,
}
}
}

/// Remove a number of internal exports that are synthesized by Rust's linker,
Expand Down Expand Up @@ -674,6 +691,12 @@ impl Output {
.with_context(|| format!("failed to write `{}`", ts_path.display()))?;
}

if gen.mode.electron_renderer() {
let preloads_path = out_dir.join("preloads").with_extension(extension);
fs::write(&preloads_path, &gen.preloads.as_ref().unwrap())
.with_context(|| format!("failed to write `{}`", preloads_path.display()))?;
}

Ok(())
}
}
Expand Down
6 changes: 5 additions & 1 deletion crates/cli/src/bin/wasm-bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Options:
--out-dir DIR Output directory
--out-name VAR Set a custom output filename (Without extension. Defaults to crate name)
--target TARGET What type of output to generate, valid
values are [web, bundler, nodejs, no-modules],
values are [web, bundler, nodejs, no-modules, electron-renderer],
and the default is [bundler]
--no-modules-global VAR Name of the global variable to initialize
--browser Hint that JS should only be compatible with a browser
Expand All @@ -35,6 +35,7 @@ Options:
--remove-producers-section Remove the telemetry `producers` section
--encode-into MODE Whether or not to use TextEncoder#encodeInto,
valid values are [test, always, never]
--electron-renderer Deprecated, use `--target electron-renderer`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's ok to not add this since there's no need to add an insta-deprecated option

--nodejs Deprecated, use `--target nodejs`
--web Deprecated, use `--target web`
--no-modules Deprecated, use `--target no-modules`
Expand All @@ -46,6 +47,7 @@ struct Args {
flag_nodejs: bool,
flag_browser: bool,
flag_web: bool,
flag_electron_renderer: bool,
flag_no_modules: bool,
flag_typescript: bool,
flag_no_typescript: bool,
Expand Down Expand Up @@ -96,12 +98,14 @@ fn rmain(args: &Args) -> Result<(), Error> {
"web" => b.web(true)?,
"no-modules" => b.no_modules(true)?,
"nodejs" => b.nodejs(true)?,
"electron-renderer" => b.electron_renderer(true)?,
s => bail!("invalid encode-into mode: `{}`", s),
};
}
b.input_path(input)
.nodejs(args.flag_nodejs)?
.web(args.flag_web)?
.electron_renderer(args.flag_electron_renderer)?
.browser(args.flag_browser)?
.no_modules(args.flag_no_modules)?
.debug(args.flag_debug)
Expand Down