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

Use ESM import in module type webworker #2220

Merged
merged 31 commits into from
Mar 2, 2022
Merged

Use ESM import in module type webworker #2220

merged 31 commits into from
Mar 2, 2022

Conversation

leopsidom
Copy link
Contributor

@leopsidom leopsidom commented Feb 26, 2022

Description

The PR is to avoid importScripts error when loading pyodide in a module type worker. Currently loadScripts uses importScripts to import dependency which throws an error when the worker is of type module.

Checklists

  • Add a CHANGELOG entry
  • Add / update tests
  • Add new / update outdated documentation

@hoodmane
Copy link
Member

Thanks @leopsidom. Maybe it would be better instead to test typeof loadScript !== "undefined" in the conditional.

@leopsidom
Copy link
Contributor Author

Thanks @leopsidom. Maybe it would be better instead to test typeof loadScript !== "undefined" in the conditional.

Do you mean test type globalThis.importScripts !== "undefined" ? I think the issue is that importScripts is still defined in both classic and module type web worker. It just throws an error when the web worker is of type module at run time.

@leopsidom
Copy link
Contributor Author

Added a check to narrow down the exception type to TypeError and rethrow other exceptions.

@hoodmane
Copy link
Member

the issue is that importScripts is still defined in both classic and module type web worker. It just throws an error when the web worker is of type module at run time.

That is unfortunate... Is there any other direct means one can use to distinguish between a module worker and a classic worker? I looked through the whatwg worker spec and I think the answer is no. Hopefully this is the only reason that importScripts would raise a TypeError though.

Copy link
Member

@hoodmane hoodmane left a comment

Choose a reason for hiding this comment

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

Ideally we should add a test for importing Pyodide as a module, both in a module worker and on the main thread, or else it might get broken again.

@leopsidom
Copy link
Contributor Author

Ideally we should add a test for importing Pyodide as a module, both in a module worker and on the main thread, or else it might get broken again.

Yeah, that makes sense. I'll take a look at adding tests for module import, though the tests won't work for module type worker in firefox yet as it's still catching up with the support at the moment.

@hoodmane
Copy link
Member

hoodmane commented Feb 27, 2022

I'll take a look at adding tests for module import

If you get stuck, let me know. You will probably want the selenium_webworker_standalone fixture, but it might be possible to use it with module scope instead of function scope which would decrease time to execute tests. Though it's good to just get something working for now and we can futz with that sort of thing later if we feel like it.

the tests won't work for module type worker in firefox yet

Sure. You can xfail it in firefox.

@leopsidom
Copy link
Contributor Author

Sure, just read a little about module and function scope, I'm not completely sure that I understands the difference.

For the tests, I'm thinking we could add a type parameter to the SeleniumWrapper class, which can be further passed to get_driver and run_webworker to import pyodide in the classic and module manner. Then we can create a separate selenium_module_webworker_standalone and selenium_module_standalone as counter part of selenium_webworker_standalone and selenium_standalone. With which we can write minimum enough tests to just make sure pyodide is loaded correctly in the module syntax. This won't reuse existing tests, so potentially not enough coverage but avoid redundant tests with assumption that after imported, the script should behave identically in both classic and module type.

@hoodmane
Copy link
Member

Sounds like a good plan to me.

There's a tradeoff we don't want to run the entire test suite in every combination of browser and webworker configuration since it would take too long. Just testing that we can successfully load Pyodide would catch the problem you reported.

@hoodmane
Copy link
Member

The issue with fixture scope is essentially how often we reload the browser tab. Refreshing the browser tab provides better isolation between tests but at the cost of taking much longer to run them.

@leopsidom
Copy link
Contributor Author

Cool. Got it. I think as long as we don't get issues on tests interacting with each other, we can definitely change the scope so it saves time on refreshing the context.

@@ -104,6 +105,8 @@ src/js/pyproxy.gen.ts : src/core/pyproxy.* src/core/*.h
build/test.html: src/templates/test.html
cp $< $@

build/module_test.html: src/templates/module_test.html
Copy link
Member

Choose a reason for hiding this comment

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

At some point we probably should try to combine some of these templates build rules (no action needed in this PR).

@leopsidom
Copy link
Contributor Author

leopsidom commented Mar 1, 2022

The test_draw_math_text in test-packages-firefox seems to fail pretty consistently in other PR: like this from the latest commit. Even for the passed test, there is a retry after the initial time out failure.

@leopsidom
Copy link
Contributor Author

Similar for this workflow from this commit.

@hoodmane
Copy link
Member

hoodmane commented Mar 1, 2022

Yeah the test failure has nothing to do with this PR.

@hoodmane
Copy link
Member

hoodmane commented Mar 1, 2022

In particular, that means the test failure won't prevent us from merging this.

@leopsidom
Copy link
Contributor Author

leopsidom commented Mar 1, 2022

In particular, that means the test failure won't prevent us from merging this.

Yeah it seems to be failing inherently due to an unknown issue. So I guess we shouldn't let it block us from merging new changes. Wonder if it's a selenium issue or firefox issue. But considering it's even xfail chrome for recursion limit, it looks like it's trying to push the limit of the browser capability.

@hoodmane
Copy link
Member

hoodmane commented Mar 1, 2022

xfailing chrome for the recursion limit must be out of date, we fixed that cf #2019

@hoodmane
Copy link
Member

hoodmane commented Mar 1, 2022

But yeah, perhaps just turning that benchmark off would be a good start.

@ryanking13
Copy link
Member

The test_draw_math_text in test-packages-firefox seems to fail pretty consistently in other PR: like this from the latest commit. Even for the passed test, there is a retry after the initial time out failure.

I am looking into it! sorry for the confusion :) (#2226)

Comment on lines +6 to +18
window.logs = [];
console.log = function (message) {
window.logs.push(message);
};
console.warn = function (message) {
window.logs.push(message);
};
console.info = function (message) {
window.logs.push(message);
};
console.error = function (message) {
window.logs.push(message);
};
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps we should move this Javascript setup out of test.html and module_test.html into tools/testsetup.js? This would reduce the duplication.

Copy link
Member

@hoodmane hoodmane Mar 2, 2022

Choose a reason for hiding this comment

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

Though maybe the issue is we specifically don't want it in node? I can't remember. I feel like I tried to move this to testsetup.js before and it didn't work. If we did move it into tools/testsetup.js all window would have to be replaced with self.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh sure, I think we could move the logic in a separate js file. I suspect node should not use the test.html file, though need to double check. I can try it at some point.

@hoodmane
Copy link
Member

hoodmane commented Mar 2, 2022

Thanks @leopsidom!

@hoodmane hoodmane merged commit 8798e1f into pyodide:main Mar 2, 2022
</script>
<script type="module">
import { loadPyodide } from "./pyodide.mjs";
window.loadPyodide = loadPyodidea;
Copy link
Member

Choose a reason for hiding this comment

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

I guess this must be a typo?

Copy link
Member

Choose a reason for hiding this comment

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

huh I wonder why that wouldn't break the tests

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, that's interesting. Let me double check ~

Copy link
Contributor Author

@leopsidom leopsidom Mar 3, 2022

Choose a reason for hiding this comment

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

Okay I think the tests pass because we already attach loadPyodide to globalThis here, while this typoed line errors out due to undefined loadPyodidea, so the line is not doing anything except throwing an error.

Copy link
Member

Choose a reason for hiding this comment

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

Thanks for the investigation. In that case we don't need to bind loadPyodide to the global in the test.html file anymore, so we would better remove those.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh I think I understand what you mean, when we call loadPyodide multiple times, we are overwriting the same Module instance.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I personally don't have much use case to load multiple pyodide instances yet. But I think it could definitely be something useful. Maybe we could wrap modules and loadPyodide in a class Pyodide and expose that class. Then every time we instantiate a new instance of Pyodide, we create a new standalone module that does not interfere with other instances.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah maybe that would work.

Copy link
Member

Choose a reason for hiding this comment

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

See #2255.

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.

None yet

3 participants