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

Module not found: Error: Can't resolve 'env' #263

Closed
jaredonline opened this issue Aug 24, 2018 · 3 comments
Closed

Module not found: Error: Can't resolve 'env' #263

jaredonline opened this issue Aug 24, 2018 · 3 comments

Comments

@jaredonline
Copy link

I'm running into an issue trying to build for wasm32-unknown-unknown, and not sure exactly where the problem is, so I'll apologize in advance if this is the wrong repo. I'll also apologize in advance for the fairly lengthy issue.

If I build a very vanilla Rust project for the web, with the following:

Cargo.toml

[package]
name = "stdwebtest"
version = "0.1.0"
authors = ["Jared McFarland <jaredonline@github.com>"]

[lib]
crate-type = ["cdylib"]

[dependencies]
cfg-if = "0.1.2"
wasm-bindgen = "0.2"

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.1", optional = true }

# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
wee_alloc = { version = "0.4.1", optional = true }

lib.rs

extern crate cfg_if;
extern crate wasm_bindgen;

mod utils;

use wasm_bindgen::prelude::*;

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(msg: &str);
}

// A macro to provide `println!(..)`-style syntax for `console.log` logging.
macro_rules! console {
    ($($t:tt)*) => (log(&format!($($t)*)))
}

#[wasm_bindgen]
extern "C" {
    fn alert(s: &str);
}

#[wasm_bindgen]
pub fn greet() {
    console!("Saying hello");
    alert("Hello, js-frontend-new!");
}

And an index.js like this:

import { greet } from "./stdwebtest.js";

greet();

And then build it as follows:

cargo +nightly build --target wasm32-unknown-unknown
wasm-bindgen target/wasm32-unknown-unknown/release/jsfrontend.wasm --out-dir .

I get an output file stdwebtest.js with the following contents (alongside the other generated artifacts like the wasm file, etc):

/* tslint:disable */
import * as wasm from './stdwebtest_bg';

const __wbg_log_9b6e4e46c0d6dfbd_target = console.log;

const TextDecoder = typeof self === 'object' && self.TextDecoder
    ? self.TextDecoder
    : require('util').TextDecoder;

let cachedDecoder = new TextDecoder('utf-8');

let cachegetUint8Memory = null;
function getUint8Memory() {
    if (cachegetUint8Memory === null || cachegetUint8Memory.buffer !== wasm.memory.buffer) {
        cachegetUint8Memory = new Uint8Array(wasm.memory.buffer);
    }
    return cachegetUint8Memory;
}

function getStringFromWasm(ptr, len) {
    return cachedDecoder.decode(getUint8Memory().subarray(ptr, ptr + len));
}

export function __wbg_log_9b6e4e46c0d6dfbd(arg0, arg1) {
    let varg0 = getStringFromWasm(arg0, arg1);
    __wbg_log_9b6e4e46c0d6dfbd_target(varg0);
}

export function __wbg_alert_ee773c68a1798d5f(arg0, arg1) {
    let varg0 = getStringFromWasm(arg0, arg1);
    alert(varg0);
}
/**
* @returns {void}
*/
export function greet() {
    return wasm.greet();
}

And I can use Webpack to serve that and it works as expected (I get an alert saying hello and a console log).

Adding stdweb

Once I add stdweb as a dependency, it breaks.

Cargo.toml

[package]
name = "stdwebtest"
version = "0.1.0"
authors = ["Jared McFarland <jaredonline@github.com>"]

[lib]
crate-type = ["cdylib"]

[dependencies]
cfg-if = "0.1.2"
wasm-bindgen = "0.2"

# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.1", optional = true }

# `wee_alloc` is a tiny allocator for wasm that is only ~1K in code size
# compared to the default allocator's ~10K. It is slower than the default
# allocator, however.
wee_alloc = { version = "0.4.1", optional = true }

stdweb = "*"

lib.rs

#[wasm_bindgen]
pub fn greet() {
    let _ = WebSocket::new("localhost:2749");
    console!("Saying hello");
    alert("Hello, js-frontend-new!");
}

And build it the same way, as soon as I try to serve it with Webpack, I get the following:

ERROR in ./stdwebtest_bg.wasm
Module not found: Error: Can't resolve 'env' in '/Users/jaredonline/jaredonline/stdweb-test'
 @ ./stdwebtest_bg.wasm
 @ ./stdwebtest.js
 @ ./index.js
 @ ./bootstrap.js
 @ multi (webpack)-dev-server/client?http://localhost:8081 ./bootstrap.js

This has led me to this issue on the Webpack repo webpack/webpack#7388 which links to this issue webpack/webpack#7352.

None of the suggestions in those issues work, and I'm not sure why. Is stdweb compiled with Emscripten by default? Is there a way to change that?

I've also tried compiling it with cargo web build --release --target wasm32-unknown-unknown, and using the generated .js and .wasm files it creates, but that has a whole new class of problems.

If its helpful I can put up a repository with all info. Any help would be appreciated!

@Pauan
Copy link
Contributor

Pauan commented Aug 24, 2018

wasm-bindgen and stdweb are incompatible (they're completely different ways of accomplishing the same thing), so you'll need to change your package to work with either one or the other.

You can take a look at the examples to see how to setup a stdweb package (it's generally much simpler and easier than a wasm-bindgen package).

@Pauan
Copy link
Contributor

Pauan commented Aug 24, 2018

If you want your package to work with both wasm-bindgen and stdweb, you'll need to use Cargo features to select at compile-time which one to use:

https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section

[dependencies]
wasm-bindgen = { version = "0.2", optional = true }
console_error_panic_hook = { version = "0.1.1", optional = true }
wee_alloc = { version = "0.4.1", optional = true }
stdweb = { version = "0.4.8", optional = true }

This will probably require you to also use cfg in your code to select between wasm-bindgen and stdweb. This will usually require some amount of code duplication:

#[cfg(feature = "wasm-bindgen")]
fn foo() -> u32 { ... }

#[cfg(feature = "stdweb")]
fn foo() -> u32 { ... }

@jaredonline
Copy link
Author

Got ya. Thank you @Pauan for the very helpful context and links.

janhohenheim added a commit to myelin-ai/myelin that referenced this issue Sep 13, 2018
The workaround is described in webpack/webpack#7352
Note that now the webserver cannot load our wasm:
"TypeError: _myelin_visualization_bg__WEBPACK_IMPORTED_MODULE_0__.init is not a function"
This might be caused by a transcient dependency on stdweb:
https://github.com/sebcrozet/nphysics/blob/master/build/nphysics2d/Cargo.toml#L31
Which is incompatible with wasm-bindgen:
koute/stdweb#263
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants