Skip to content

Commit

Permalink
Enable node module output format
Browse files Browse the repository at this point in the history
  • Loading branch information
Systemcluster committed Jul 30, 2024
1 parent cdcbaf1 commit d67e885
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 91 deletions.
98 changes: 49 additions & 49 deletions crates/cli-support/src/js/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,7 @@ impl<'a> Context<'a> {
self.globals.push_str(c);
}
let global = match self.config.mode {
OutputMode::Node {
experimental_modules: false,
} => {
OutputMode::Node { module: false } => {
if contents.starts_with("class") {
format!("{}\nmodule.exports.{1} = {1};\n", contents, export_name)
} else {
Expand All @@ -159,9 +157,7 @@ impl<'a> Context<'a> {
}
}
OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
}
| OutputMode::Node { module: true }
| OutputMode::Web
| OutputMode::Deno => {
if let Some(body) = contents.strip_prefix("function") {
Expand Down Expand Up @@ -219,7 +215,7 @@ impl<'a> Context<'a> {

shim.push_str("let imports = {};\n");

if self.config.mode.nodejs_experimental_modules() {
if self.config.mode.uses_es_modules() {
for (i, module) in imports.iter().enumerate() {
if module.as_str() != PLACEHOLDER_MODULE {
shim.push_str(&format!("import * as import{} from '{}';\n", i, module));
Expand All @@ -233,7 +229,7 @@ impl<'a> Context<'a> {
"imports['{0}'] = module.exports;\n",
PLACEHOLDER_MODULE
));
} else if self.config.mode.nodejs_experimental_modules() {
} else if self.config.mode.uses_es_modules() {
shim.push_str(&format!("imports['{}'] = import{};\n", module, i));
} else {
shim.push_str(&format!("imports['{0}'] = require('{0}');\n", module));
Expand All @@ -246,24 +242,30 @@ impl<'a> Context<'a> {
fn generate_node_wasm_loading(&self, path: &Path) -> String {
let mut shim = String::new();

if self.config.mode.nodejs_experimental_modules() {
if self.config.mode.uses_es_modules() {
// On windows skip the leading `/` which comes out when we parse a
// url to use `C:\...` instead of `\C:\...`
shim.push_str(&format!(
"
import * as path from 'path';
import * as fs from 'fs';
import * as url from 'url';
import * as process from 'process';
import * as path from 'node:path';
import * as fs from 'node:fs';
import * as process from 'node:process';
let file = path.dirname(url.parse(import.meta.url).pathname);
let file = path.dirname(new URL(import.meta.url).pathname);
if (process.platform === 'win32') {{
file = file.substring(1);
}}
const bytes = fs.readFileSync(path.join(file, '{}'));
",
path.file_name().unwrap().to_str().unwrap()
));
shim.push_str(
"
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
export const wasm = wasmInstance.exports;
",
);
} else {
shim.push_str(&format!(
"
Expand All @@ -272,17 +274,16 @@ impl<'a> Context<'a> {
",
path.file_name().unwrap().to_str().unwrap()
));
shim.push_str(
"
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
wasm = wasmInstance.exports;
module.exports.__wasm = wasm;
",
);
}

shim.push_str(
"
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
wasm = wasmInstance.exports;
module.exports.__wasm = wasm;
",
);

reset_indentation(&shim)
}

Expand Down Expand Up @@ -400,9 +401,7 @@ impl<'a> Context<'a> {

// With normal CommonJS node we need to defer requiring the wasm
// until the end so most of our own exports are hooked up
OutputMode::Node {
experimental_modules: false,
} => {
OutputMode::Node { module: false } => {
js.push_str(&self.generate_node_imports());

js.push_str("let wasm;\n");
Expand Down Expand Up @@ -442,13 +441,10 @@ impl<'a> Context<'a> {
}
}

// With Bundlers and modern ES6 support in Node we can simply import
// the wasm file as if it were an ES module and let the
// bundler/runtime take care of it.
OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
} => {
// With Bundlers we can simply import the wasm file as if it were an ES module
// and let the bundler/runtime take care of it.
// With Node we manually read the wasm file from the filesystem and instantiate it.
OutputMode::Bundler { .. } | OutputMode::Node { module: true } => {
for (id, js) in crate::sorted_iter(&self.wasm_import_definitions) {
let import = self.module.imports.get_mut(*id);
import.module = format!("./{}_bg.js", module_name);
Expand All @@ -466,14 +462,22 @@ impl<'a> Context<'a> {
}
}

self.imports_post.push_str(
"\
if matches!(self.config.mode, OutputMode::Node { module: true }) {
imports.push_str(&self.generate_node_imports());
imports.push_str(&self.generate_node_wasm_loading(Path::new(&format!(
"./{}_bg.wasm",
module_name
))));
} else {
self.imports_post.push_str(
"\
let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}
",
);
);
}

if needs_manual_start {
start = Some("\nwasm.__wbindgen_start();\n".to_string());
Expand Down Expand Up @@ -509,7 +513,9 @@ impl<'a> Context<'a> {
// Emit all the JS for importing all our functionality
assert!(
!self.config.mode.uses_es_modules() || js.is_empty(),
"ES modules require imports to be at the start of the file"
"ES modules require imports to be at the start of the file, but we \
generated some JS before the imports: {}",
js
);

let mut push_with_newline = |s| {
Expand Down Expand Up @@ -556,9 +562,7 @@ impl<'a> Context<'a> {
}
}

OutputMode::Node {
experimental_modules: false,
} => {
OutputMode::Node { module: false } => {
for (module, items) in crate::sorted_iter(&self.js_imports) {
imports.push_str("const { ");
for (i, (item, rename)) in items.iter().enumerate() {
Expand All @@ -582,9 +586,7 @@ impl<'a> Context<'a> {
}

OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
}
| OutputMode::Node { module: true }
| OutputMode::Web
| OutputMode::Deno => {
for (module, items) in crate::sorted_iter(&self.js_imports) {
Expand Down Expand Up @@ -3216,12 +3218,10 @@ impl<'a> Context<'a> {
OutputMode::Web
| OutputMode::Bundler { .. }
| OutputMode::Deno
| OutputMode::Node {
experimental_modules: true,
} => "import.meta.url",
OutputMode::Node {
experimental_modules: false,
} => "require('url').pathToFileURL(__filename)",
| OutputMode::Node { module: true } => "import.meta.url",
OutputMode::Node { module: false } => {
"require('url').pathToFileURL(__filename)"
}
OutputMode::NoModules { .. } => {
prelude.push_str(
"if (script_src === undefined) {
Expand Down
67 changes: 25 additions & 42 deletions crates/cli-support/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ enum OutputMode {
Bundler { browser_only: bool },
Web,
NoModules { global: String },
Node { experimental_modules: bool },
Node { module: bool },
Deno,
}

Expand Down Expand Up @@ -154,24 +154,14 @@ impl Bindgen {

pub fn nodejs(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: false,
},
"--target nodejs",
)?;
self.switch_mode(OutputMode::Node { module: false }, "--target nodejs")?;
}
Ok(self)
}

pub fn nodejs_experimental_modules(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
pub fn nodejs_module(&mut self, node: bool) -> Result<&mut Bindgen, Error> {
if node {
self.switch_mode(
OutputMode::Node {
experimental_modules: true,
},
"--nodejs-experimental-modules",
)?;
self.switch_mode(OutputMode::Node { module: true }, "--target nodejs-module")?;
}
Ok(self)
}
Expand Down Expand Up @@ -548,22 +538,11 @@ impl OutputMode {
self,
OutputMode::Bundler { .. }
| OutputMode::Web
| OutputMode::Node {
experimental_modules: true,
}
| OutputMode::Node { module: true }
| OutputMode::Deno
)
}

fn nodejs_experimental_modules(&self) -> bool {
match self {
OutputMode::Node {
experimental_modules,
} => *experimental_modules,
_ => false,
}
}

fn nodejs(&self) -> bool {
matches!(self, OutputMode::Node { .. })
}
Expand All @@ -579,10 +558,7 @@ impl OutputMode {
fn esm_integration(&self) -> bool {
matches!(
self,
OutputMode::Bundler { .. }
| OutputMode::Node {
experimental_modules: true,
}
OutputMode::Bundler { .. } | OutputMode::Node { module: true }
)
}
}
Expand Down Expand Up @@ -687,11 +663,7 @@ impl Output {

// And now that we've got all our JS and TypeScript, actually write it
// out to the filesystem.
let extension = if gen.mode.nodejs_experimental_modules() {
"mjs"
} else {
"js"
};
let extension = "js";

fn write<P, C>(path: P, contents: C) -> Result<(), anyhow::Error>
where
Expand All @@ -709,17 +681,28 @@ impl Output {

let start = gen.start.as_deref().unwrap_or("");

write(
&js_path,
format!(
"import * as wasm from \"./{wasm_name}.wasm\";
if matches!(gen.mode, OutputMode::Node { .. }) {
write(
&js_path,
format!(
"
export * from \"./{js_name}\";
{start}",
),
)?;
} else {
write(
&js_path,
format!(
"
import * as wasm from \"./{wasm_name}.wasm\";
import {{ __wbg_set_wasm }} from \"./{js_name}\";
__wbg_set_wasm(wasm);
export * from \"./{js_name}\";
{start}"
),
)?;

),
)?;
}
write(out_dir.join(&js_name), reset_indentation(&gen.js))?;
} else {
write(&js_path, reset_indentation(&gen.js))?;
Expand Down
1 change: 1 addition & 0 deletions crates/cli/src/bin/wasm-bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ fn rmain(args: &Args) -> Result<(), Error> {
"web" => b.web(true)?,
"no-modules" => b.no_modules(true)?,
"nodejs" => b.nodejs(true)?,
"nodejs-module" => b.nodejs_module(true)?,
"deno" => b.deno(true)?,
s => bail!("invalid encode-into mode: `{}`", s),
};
Expand Down

0 comments on commit d67e885

Please sign in to comment.