diff --git a/crates/backend/src/ast.rs b/crates/backend/src/ast.rs index 4c317cea44f..75c73860275 100644 --- a/crates/backend/src/ast.rs +++ b/crates/backend/src/ast.rs @@ -79,6 +79,7 @@ pub struct Import { pub enum ImportModule { None, Named(String, Span), + RawNamed(String, Span), Inline(usize, Span), } @@ -96,6 +97,10 @@ impl Hash for ImportModule { 2u8.hash(h); idx.hash(h); } + ImportModule::RawNamed(name, _) => { + 3u8.hash(h); + name.hash(h); + } } } } diff --git a/crates/backend/src/encode.rs b/crates/backend/src/encode.rs index abc8c613762..2e327d20253 100644 --- a/crates/backend/src/encode.rs +++ b/crates/backend/src/encode.rs @@ -208,6 +208,7 @@ fn shared_import<'a>(i: &'a ast::Import, intern: &'a Interner) -> Result { ImportModule::Named(intern.resolve_import_module(m, *span)?) } + ast::ImportModule::RawNamed(m, _span) => ImportModule::RawNamed(intern.intern_str(m)), ast::ImportModule::Inline(idx, _) => ImportModule::Inline(*idx as u32), ast::ImportModule::None => ImportModule::None, }, diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index 57e90368eb8..cdd2ea57af4 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -2836,6 +2836,7 @@ impl<'a, 'b> SubContext<'a, 'b> { // not sure how to import them. let is_local_snippet = match import.module { decode::ImportModule::Named(s) => self.cx.local_modules.contains_key(s), + decode::ImportModule::RawNamed(_) => false, decode::ImportModule::Inline(_) => true, decode::ImportModule::None => false, }; @@ -2921,11 +2922,13 @@ impl<'a, 'b> SubContext<'a, 'b> { name, field, }, - decode::ImportModule::Named(module) => Import::Module { - module, - name, - field, - }, + decode::ImportModule::Named(module) | decode::ImportModule::RawNamed(module) => { + Import::Module { + module, + name, + field, + } + } decode::ImportModule::Inline(idx) => { let offset = *self .cx diff --git a/crates/macro-support/src/parser.rs b/crates/macro-support/src/parser.rs index 574af3c27ed..d94a468070c 100644 --- a/crates/macro-support/src/parser.rs +++ b/crates/macro-support/src/parser.rs @@ -33,6 +33,7 @@ macro_rules! attrgen { (static_method_of, StaticMethodOf(Span, Ident)), (js_namespace, JsNamespace(Span, Ident)), (module, Module(Span, String, Span)), + (raw_module, RawModule(Span, String, Span)), (inline_js, InlineJs(Span, String, Span)), (getter, Getter(Span, Option)), (setter, Setter(Span, Option)), @@ -1085,24 +1086,28 @@ impl MacroParse for syn::ItemForeignMod { )); } } - let module = match opts.module() { - Some((name, span)) => { - if opts.inline_js().is_some() { - let msg = "cannot specify both `module` and `inline_js`"; - errors.push(Diagnostic::span_error(span, msg)); - } - ast::ImportModule::Named(name.to_string(), span) + let module = if let Some((name, span)) = opts.module() { + if opts.inline_js().is_some() { + let msg = "cannot specify both `module` and `inline_js`"; + errors.push(Diagnostic::span_error(span, msg)); } - None => { - match opts.inline_js() { - Some((js, span)) => { - let i = program.inline_js.len(); - program.inline_js.push(js.to_string()); - ast::ImportModule::Inline(i, span) - } - None => ast::ImportModule::None - } + if opts.raw_module().is_some() { + let msg = "cannot specify both `module` and `raw_module`"; + errors.push(Diagnostic::span_error(span, msg)); } + ast::ImportModule::Named(name.to_string(), span) + } else if let Some((name, span)) = opts.raw_module() { + if opts.inline_js().is_some() { + let msg = "cannot specify both `raw_module` and `inline_js`"; + errors.push(Diagnostic::span_error(span, msg)); + } + ast::ImportModule::RawNamed(name.to_string(), span) + } else if let Some((js, span)) = opts.inline_js() { + let i = program.inline_js.len(); + program.inline_js.push(js.to_string()); + ast::ImportModule::Inline(i, span) + } else { + ast::ImportModule::None }; for item in self.items.into_iter() { if let Err(e) = item.macro_parse(program, module.clone()) { diff --git a/crates/shared/src/lib.rs b/crates/shared/src/lib.rs index 9b9356f2498..5bd0072cd23 100644 --- a/crates/shared/src/lib.rs +++ b/crates/shared/src/lib.rs @@ -28,6 +28,7 @@ macro_rules! shared_api { enum ImportModule<'a> { None, Named(&'a str), + RawNamed(&'a str), Inline(u32), } diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md index 077c50cbe3b..530b1286b7e 100644 --- a/guide/src/SUMMARY.md +++ b/guide/src/SUMMARY.md @@ -66,6 +66,7 @@ - [`js_namespace`](./reference/attributes/on-js-imports/js_namespace.md) - [`method`](./reference/attributes/on-js-imports/method.md) - [`module = "blah"`](./reference/attributes/on-js-imports/module.md) + - [`raw_module = "blah"`](./reference/attributes/on-js-imports/raw_module.md) - [`static_method_of = Blah`](./reference/attributes/on-js-imports/static_method_of.md) - [`structural`](./reference/attributes/on-js-imports/structural.md) - [`variadic`](./reference/attributes/on-js-imports/variadic.md) diff --git a/guide/src/reference/attributes/on-js-imports/module.md b/guide/src/reference/attributes/on-js-imports/module.md index 4f6b4408e7c..24643e42c73 100644 --- a/guide/src/reference/attributes/on-js-imports/module.md +++ b/guide/src/reference/attributes/on-js-imports/module.md @@ -31,3 +31,8 @@ generates JavaScript import glue like: ```js let illmatic = this.illmatic; ``` + +Note that if the string specified with `module` starts with `./`, `../`, or `/` +then it's interpreted as a path to a [local JS snippet](../../js-snippets.html). +If this doesn't work for your use case you might be interested in the +[`raw_module` attribute](raw_module.html) diff --git a/guide/src/reference/attributes/on-js-imports/raw_module.md b/guide/src/reference/attributes/on-js-imports/raw_module.md new file mode 100644 index 00000000000..1f8da2f3dfb --- /dev/null +++ b/guide/src/reference/attributes/on-js-imports/raw_module.md @@ -0,0 +1,19 @@ +# `raw_module = "blah"` + +This attribute performs exactly the same purpose as the [`module` +attribute](module.html) on JS imports, but it does not attempt to interpret +paths starting with `./`, `../`, or `/` as JS snippets. For example: + +```rust +#[wasm_bindgen(raw_module = "./some/js/file.js")] +extern "C" { + fn the_function(); +} +``` + +Note that if you use this attribute with a relative or absolute path, it's +likely up to the final bundler or project to assign meaning to that path. This +typically means that the JS file or module will be resolved relative to the +final location of the wasm file itself. That means that `raw_module` is likely +unsuitable for libraries on crates.io, but may be usable within end-user +applications.