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

fix: clearTimeout illegal invocation with bundler (#187) #283

Merged
merged 4 commits into from
Jan 20, 2023

Conversation

flisky
Copy link
Contributor

@flisky flisky commented Jan 10, 2023

It's a regression from #96 introduced by #185, and I have no idea why calling clearTimeout is failed in browser, but my patch definitely resolves the error.

It's a side effect introduced by bundler, and we workaround it. more details in #283 (comment)

Copy link
Collaborator

@futursolo futursolo left a comment

Choose a reason for hiding this comment

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

Interestingly, the current timer implementation (in master) does not seem to work with wasm-pack test --node either when I tried it. Maybe this will also fix it?

CI should turn green when if you rebase from the master branch.

crates/timers/src/callback.rs Outdated Show resolved Hide resolved
@DogLooksGood
Copy link

FYI, ran into this with https://github.com/paritytech/jsonrpsee. What weird is, current version (gloo-timers 0.2.5) only works in tests, not in real cases. In wasm-pack test --chrome it works (when I open the browser to run tests). But if the it is compiled to wasm (with wasm-pack) and required by JavaScript, there's an illegal invocation error.

@flisky
Copy link
Contributor Author

flisky commented Jan 19, 2023

@futursolo good catch. It turns out the return type is different between browser (number) / nodejs (Timeout), and I push another commit for nodejs support.

@flisky
Copy link
Contributor Author

flisky commented Jan 19, 2023

@DogLooksGood @futursolo I take a deep look at ctm/gloo-timers-regression(thanks @ctm), and reproduce as the following code:

const foo = { bar: clearTimeout }
foo.bar()

It's a clearly true invocation error because clearTimeout is binding this to foo, instead of Window.


And setTimeout is not affected because the wasm-pack generates the following code:

function() { return handleError(function (arg0, arg1) {
    const ret = setTimeout(getObject(arg0), arg1);
    _assertNum(ret);
    return ret;
}, arguments) };

while clearTimeout goes to typeof clearTimeout == 'function' ? clearTimeout : notDefined('clearTimeout')

So, it's a bad side-effect introduced by bundler.


The currently clearTimeout goes to

function() { return logError(function (arg0, arg1) {
   getObject(arg0).clearTimeout(takeObject(arg1));
}, arguments) };

I think we can hack the binding further into

#[wasm_bindgen(js_name = "clearTimeout")]
fn clear_timeout(handle: JsValue) -> JsValue;

which generates

 function() { return logError(function (arg0) {
    const ret = clearTimeout(takeObject(arg0));
    return addHeapObject(ret);
}, arguments) }

@flisky flisky changed the title fix: clearTimeout illegal invocation in browser (#187) fix: clearTimeout illegal invocation with bundler (#187) Jan 19, 2023
@DogLooksGood
Copy link

@flisky I just tried with your master version, the issue hasn't solved in my case. The generated code is still

export const __wbg_clearTimeout_23ee6db72c0ad922 = typeof clearTimeout == 'function' ? clearTimeout : notDefined('clearTimeout');

@flisky
Copy link
Contributor Author

flisky commented Jan 20, 2023

@DogLooksGood, could you please double check? Make sure that:

  • something like git+https://github.com/flisky/gloo.git#74a5769b5e6def8fdcc11179378a1afcd1bacb7a in Cargo.lock
  • disable cache in devtools when reproducing

@flisky
Copy link
Contributor Author

flisky commented Jan 20, 2023

@futursolo, could you please take another review?

There're two binding changes:

  • the return type of setTimeout/setInterval from i32 to JsValue to support nodejs, which returns Timeout object.
  • add return type of clearTimeout/clearInterval to let wasm-bindgen wrapping the generated code, to avoid a bare function call in a different namespace.

I don't know how to run the same testcases in nodejs & browser with wasm-bindgen test, so I duplicates web.rs into node.rs. Please let me known if there's a better way. Thanks!

@futursolo
Copy link
Collaborator

The implementation looks good to me. I will approve this once I hear back from @DogLooksGood.

I don't know how to run the same testcases in nodejs & browser with wasm-bindgen test, so I duplicates web.rs into node.rs. Please let me known if there's a better way. Thanks!

You can apply a feature flag to run_in_browser.

// It might be better to use not(node_tests) than browser_tests because most existing tests are browser tests.

#[cfg(not(feature = "node_tests"))]
wasm_bindgen_test_configure!(run_in_browser);
// Runs browser tests
wasm-pack test --firefox

// Runs node tests
wasm-pack test --features=node_tests --node

In addition, would you mind to also update GitHub Actions to run node tests?

@DogLooksGood
Copy link

@futursolo @flisky Sorry, it's my fault. It works.

@flisky
Copy link
Contributor Author

flisky commented Jan 20, 2023

@futursolo the current CI is heavily based on --all-features, and I don't think web_tests/node_tests works perfectly with other feature flags.

Tests / Node Tests job is setup, and works as expected

@futursolo
Copy link
Collaborator

Whilst I think it's still possible to combine tests with a compiler flag, I am fine with merging this pull request as-is.

We can merge the tests together in the future.

@futursolo futursolo merged commit 01c127c into rustwasm:master Jan 20, 2023
@ranile
Copy link
Collaborator

ranile commented Jan 21, 2023

Released in gloo-timers 0.2.6 🎉

jsdanielh added a commit to jsdanielh/rust-libp2p that referenced this pull request Nov 19, 2023
Add support different WASM environments (such as workers, NodeJS)
that don't have a `window` global by binding to the global
`setInterval` and `clearInterval` functions directly.
This uses the same approach as used by gloo-timers implemented in
[rustwasm/gloo#185](rustwasm/gloo#185) and
[rustwasm/gloo#283](rustwasm/gloo#283) given
the `web-sys` lack of interes to support this (see discussion in
[this issue](rustwasm/wasm-bindgen#1046)).

Co-authored-by: sisou <hello@soerenschwert.de>
jsdanielh added a commit to jsdanielh/rust-libp2p that referenced this pull request Nov 19, 2023
Add support different WASM environments (such as workers, NodeJS)
that don't have a `window` global. This is done by binding to the
global `setInterval` and `clearInterval` functions directly.
This uses the same approach used by gloo-timers implemented in
[rustwasm/gloo#185](rustwasm/gloo#185) and
[rustwasm/gloo#283](rustwasm/gloo#283) given
the `web-sys` lack of interes to support this (see discussion in
[this issue](rustwasm/wasm-bindgen#1046)).

Co-authored-by: sisou <hello@soerenschwert.de>
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

Successfully merging this pull request may close these issues.

4 participants