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

Cannot execute Classic Worker in dev mode due to imports injected by Vite #7019

Closed
7 tasks done
g-plane opened this issue Feb 21, 2022 · 6 comments · Fixed by #7099
Closed
7 tasks done

Cannot execute Classic Worker in dev mode due to imports injected by Vite #7019

g-plane opened this issue Feb 21, 2022 · 6 comments · Fixed by #7099
Labels
feat: web workers p3-minor-bug An edge case that only affects very specific usage (priority)

Comments

@g-plane
Copy link
Contributor

g-plane commented Feb 21, 2022

Describe the bug

Problem

When I created and executed a classic Web Worker in dev mode, browsers will throw an error:

Uncaught SyntaxError: Cannot use import statement outside a module

Here is how I created the classic Web Worker:

const classicWorker = new Worker(new URL('./worker.js', import.meta.url));

classicWorker.addEventListener('message', ({ data }) => {
  // do something
});
classicWorker.postMessage('ping');

And, here is the Web Worker file. Note that it doesn't contain any import statements or dynamic imports:

self.addEventListener('message', () => {
  self.postMessage('pong');
});

Possible Reason

In dev mode, Vite will inject a special module /@vite/env for shimming environment variables, and it will introduce an import statement. The internal "worker" and "workerImportMetaUrl" plugin inject:

code: `import '${ENV_PUBLIC_PATH}'\n` + _

code: `import '${ENV_PUBLIC_PATH}'\n` + code

Then, the worker script will become: (for the example I mentioned above)

import '/@vite/env'
self.addEventListener('message', () => {
  self.postMessage('pong');
});

Because import statements aren't allowed in classic Web Worker, browsers threw that error.

Possible Solution

I tried using importScripts which is available in Web Worker to import that /@vite/env module. It works for my case, since it's a Classic Worker, not a Module Worker.

importScripts('/@vite/env'); // It works here.
// ...

However, when running Vite's tests, they failed. It reported:

Failed to execute 'importScripts' on 'WorkerGlobalScope': Module scripts don't support importScripts().

so I don't have ideas about fixing this problem.

Q & A

  • Q: Can I just switch to Module Worker? Vite will bundle it in build mode.
    A: No, because in my real case, that snippet about creating worker (new Worker(/* */)) comes from a third-party library, which I'm not able to control. Also, I use Firefox, fixing this bug would be better.

Reproduction

https://stackblitz.com/edit/vitejs-vite-y9bsxv?file=main.js&terminal=dev

System Info

Browsers:
Chrome 98.0.4758.102
Firefox 97.0.1
Microsoft Edge 98.0.1108.50

Used Package Manager

pnpm

Logs

No response

Validations

@g-plane g-plane added p3-minor-bug An edge case that only affects very specific usage (priority) feat: web workers labels Feb 21, 2022
@poyoho
Copy link
Member

poyoho commented Feb 25, 2022

workerOptions type=module only support import expression and type=classic only support importScript.

if make all worker to type=module, the plugin-legacy can't compatible classic worker 🥲

@poyoho
Copy link
Member

poyoho commented Feb 25, 2022

if use user config and code is dynamic. can't match all.

PS: { type: fn() }

@poyoho
Copy link
Member

poyoho commented Feb 25, 2022

I think the compatibility mode should be a global configuration. Maybe we can provide a configuration that all workers are module or classic ?

@bluwy
Copy link
Member

bluwy commented Feb 25, 2022

if use user config and code is dynamic. can't match all.

PS: { type: fn() }

I think it would be fair to assume that type will always be static. Vite has certain assumptions about syntax like this, e.g. for import.meta.glob assert raw, and new URL(..., import.meta.url) 🤔

@g-plane
Copy link
Contributor Author

g-plane commented Feb 25, 2022

I think the compatibility mode should be a global configuration. Maybe we can provide a configuration that all workers are module or classic ?

It may be not perfect, but at least it should work.

@patak-dev
Copy link
Member

I think we can detect the case where { type: 'module' } is not provided or { type: 'classic' } is passed with a static string and use classic workers. As @bluwy said, there are other places where we do the same. If a dynamic expression appears, we can issue an error. Or give the user a way out of Vite processing. We currently don't support this case anyways, no? Also, I don't think there are a lot of use cases for a dynamic worker type in the context of a Vite app

@github-actions github-actions bot locked and limited conversation to collaborators Mar 18, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
feat: web workers p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants