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

documentation: Web Worker Support #1280

Closed
3 of 4 tasks
FredKSchott opened this issue Oct 11, 2020 · 8 comments
Closed
3 of 4 tasks

documentation: Web Worker Support #1280

FredKSchott opened this issue Oct 11, 2020 · 8 comments
Labels

Comments

@FredKSchott
Copy link
Owner

FredKSchott commented Oct 11, 2020

Background

Now that Webpack can detect native web worker usage (new Worker(new URL("./worker.js", import.meta.url))) and bundle automatically, we can claim native web worker support. We've always had this support in snowpack, but due to the lack of support for this in older browsers you were limited by where you could run your application in production.

Now that Webpack 5 automatically bundles this, you have support in both dev and prod.

Feature Request

  • Document how to use a web worker (not snowpack specific)
  • Document the limitation that only Chrome and Edge support ESM import/export in workers, so you'll need to dev in one of those browsers. https://caniuse.com/mdn-api_worker_worker_ecmascript_modules
  • Document that this is only a limitation of development, not production. When you build for production, the webpack bundler will automatically bundle this for production to run on all browsers.
  • BONUS: Add a test that validates this behavior.
@ashwanth1109
Copy link
Contributor

ashwanth1109 commented Oct 25, 2020

@FredKSchott , I have been looking into this issue and I'm running into a bit of a snag.

I followed the documentation in webpack on how to setup a web worker with workbox. But Im running into a bit of a snag.

This is the error I get:
2020-10-26 05_05_22-Progressive Web Application

These are the changes I made as per the webpack documentation

Is this something you can help me out with? If thats not feasible, I do plan to raise an issue on webpack github repo to be able to get it to work.

@ashwanth1109
Copy link
Contributor

ashwanth1109 commented Oct 25, 2020

@Gregoor
Copy link

Gregoor commented Nov 18, 2020

Heya, thanks for snowpack, really enjoying it so far. Running into a bit of a problem where FF&Safari won't work because both of the WebWorker implementations don't seem to support import-ing from inside a worker. Any idea for a workaround within snowpack?

edit: realized this is about documentation, I should probably take it elsewhere 🙊

@twop
Copy link

twop commented Nov 27, 2020

I have a difficulty configuring this setup:

  • Typescript
  • WebWorker
  • WASM inside WebWorker

currently, my code looks like this:

const worker = new Worker('./worker.js');
worker.onmessage = ({ data }) => console.log('From Worker ->', data);
worker.postMessage(MsgToWorker.HiWorker);

Note I do have worker.ts file.

In DEV

With that code I get

GET http://localhost:8080/worker.js 404 (Not Found)

if I change my code to

const worker = new Worker('./worker.ts'); // <---- .ts

I got the same 404 response.

In PROD

When I generate with worker.ts in the source I get this:

// generated code
const worker = new Worker('./worker.ts'); // <-- should it be .js?

Thus, I don't know how to configure that properly :(

UPD

I was able to start fetching a worker with this:

const worker = new Worker('./_dist_/worker.js'); // <-- .js + _dist_

Which seems unintuitive to me.
Even though I was able to produce a fetch requests for the worker, the top level console.log() in worker.js didn't work (neither postMessage) :(

@cortopy
Copy link

cortopy commented Dec 2, 2020

I was also caught by the need to add the './_dist_/ prefix to the worker uri

@FredKSchott I think this might be snowpack specific, and so maybe worth adding to your checklist for this issue?

@cortopy
Copy link

cortopy commented Dec 3, 2020

I've been trying web workers with snowpack, and I've come up with the required steps to make it work (ish)

This snippet should nearly work:

const worker = new Worker(
        new URL('../../../my-worker.js', import.meta.url),
        {
          name: 'my-web-worker',
          type: import.meta.env.MODE === 'development' ? "module" : "classic"
        }
      );

Some notes for the documentation:

When creating a Worker, snowpack relies on the native support from webpack 5. The first argument of the Worker is a URI with the location of the file in the final bundle. Please note that this URI is not fully resolvable against your local filesystem. The URI should point to the address where the browser can get the web worker file. In order to help Webpack to create the right URI, we have to pass import.meta.url as the URL context. See the release notes for this new feature

When using typescript, the file extension should always be .js.

The second argument of the Worker is an object with options. In development, Snowpack will emit a module and we need to pass that configuration to the Worker constructor. Otherwise, the script won't be able to import any dependencies. Please note, that support for web worker modules is limited at the moment

In production, however, the type of your web worker will depend on the build configuration. If not using module as output, then "classic" is the preferred option.

TODO

I would gladly formalise these notes in a PR. However, there is still something that I couldn't get to work.

Snowpack's hmr-client has a reference to window which doesn't play nice in the web worker's module since window will never be defined as a global. I've patched this file on my end and all seems good so far. Would removing that reference to window be feasible? Again, happy to open a PR for that one too

@FredKSchott
Copy link
Owner Author

Tackling in #2027

@Birch-san
Copy link
Contributor

Birch-san commented Apr 10, 2021

Here's how I bundled web workers: (Close but no cigar; see edit below)
Birch-san/liquidfun-play#2

  1. install unofficial webpack 5 plugin @efox/snowpack-plugin-webpack5
  1. load Worker as { type: 'classic' } in production bundle:
const worker = new Worker(new URL('./worker.js', import.meta.url), {
  type: import.meta.env.MODE === 'development' ? 'module' : 'classic'
})
  1. modify the webpack config

We use Webpack's DefinePlugin to make available at compile-time a global variable __SNOWPACK_ENV__ with value "production":

snowpack.config.js

const { DefinePlugin } = require('webpack')

/** @type {import("snowpack").SnowpackUserConfig } */
module.exports = {
 plugins: [
    ['@efox/snowpack-plugin-webpack5', {
      /** @param {import("webpack").Configuration } config */
      extendConfig: (config) => {
        config.plugins.push(new DefinePlugin({
          __SNOWPACK_ENV__: JSON.stringify('production')
        }))
        return config
      }
    }]
  1. enjoy your bundle
snowpack build

You can also refer to my pull request for an example of how to serve the bundle via a local webserver.

EDIT:
Actually, nevermind -- I may have spoken too soon. Yes, this sufficed to make Webpack 5 work for me, but I'm still seeing that my workers continue to use ES imports (and need further bundling). Nevertheless, hopefully this serves usefully as a first step.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants