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

How to use Web Workers using the approach from repository? #1

Closed
WRCIECH opened this issue Apr 30, 2023 · 3 comments
Closed

How to use Web Workers using the approach from repository? #1

WRCIECH opened this issue Apr 30, 2023 · 3 comments

Comments

@WRCIECH
Copy link

WRCIECH commented Apr 30, 2023

Hey,

thank you for the blog post, it was very helpful to me!

I encountered troubles when I tried to use web worker using this approach:

In App.vue:

let worker = new Worker('./task.js', {type: 'module'});

and create task.js with some implementation there.

This addition leads to error that instead of expected .js module the .html file is returned from the server.

I currently use workaround just by doing:

app.get("/task.js", (_req, res) => {
    res.type('.js')
    const dest = path.join(path.resolve(), "src");
    res.sendFile('task.js', {root: dest});
});

but this approach requires to manually reload page for every change done in the worker file (and anything else that the worker uses; webassembly file in my case).

Is there a better approach than this?
Is there a way to make worker treated the same way as other javascript files?

@WRCIECH WRCIECH changed the title How to How to use Web Workers using the approach from repository? Apr 30, 2023
@rhian-cs
Copy link
Owner

Hi @WRCIECH ! I'm glad the blogpost was useful to you!

I'll be honest with you, I haven't looked at Web Workers up until now, but I can look into that for a few weeks in order to think of a solution.

But looking at the description of your problem, I believe the web worker file (task.js) and the .wasm files would have to be treated the same as any other static asset, and would not be automatically reloaded.

So you could test some approaches, such as:

  • Putting the files under /public, so that they would always be accessible by the front-end
  • Putting the files under /src/assets and adding .js files to the supportedAssets array under the server/assetsRouter.js file
  • Creating another router for JS assets file (I'll see if I can write a code sample for that)

You could also consider using an external library such as vue-worker to interact with the worker: https://www.digitalocean.com/community/tutorials/vuejs-vue-workers. But I'm not sure how that would work with WASM files.

In any case, I'll try to look for solution in my spare time, let me know if any of these approaches work for you!

@rhian-cs
Copy link
Owner

rhian-cs commented May 7, 2023

Hey @WRCIECH ! I've taken another look at the issue, and I think I've found an optimal solution to your problem.

The Vite documentation actually supports Web Worker assets, take a look at the following links:

And the best part is that it supports hot reloading as well!

(by the way, it also seems to support WASM files but I haven't looked into it: https://vitejs.dev/guide/features.html#webassembly)

To implement this, first import your Web Worker in your front-end component or JS file using the web worker syntax for Vite, e.g. in src/App.vue:

<script setup>
import HelloWorld from "./components/HelloWorld.vue";

import MyWorker from "./workers/myWorker?worker";

const worker = new MyWorker();
</script>

<template>
  <!-- ... -->
</template>

<style scoped>
  /* ... */
</style>

Then create your worker under the src/ directory, for this example I've put it in src/workers/myWorker.js with a simple console.log("Hello from Web Worker!"); statement as the content.

However, this doesn't work just yet because we have to add support for .js files in our assets router, like this:

// server/assetsRouter.js

// ...

const supportedAssets = ["svg", "png", "jpg", "png", "jpeg", "mp4", "ogv", "js",];

I also realized that redirecting assets doesn't work for JS assets. So to fix this, instead of redirecting the assets we can just proxy them to the Vite server.

To make this work, I've replaced the router.get statement in the server/assetsRouter.js file for the following:

import express from "express";
import http from "http";

// ...

router.get(assetExtensionRegex(), (req, res) => {
  proxyRequest(req, res, `http://localhost:5173/src${req.path}`);
});

// Adapted from this SO answer: https://stackoverflow.com/questions/20351637/how-to-create-a-simple-http-proxy-in-node-js#20354642
const proxyRequest = (clientReq, clientRes, url) => {
  const proxy = http.request(url, (proxyRes) => {
    clientRes.writeHead(proxyRes.statusCode, proxyRes.headers);
    proxyRes.pipe(clientRes, { end: true });
  });

  clientReq.pipe(proxy, { end: true });
};

One final problem that I had is that editing the Web Worker JS file also triggered a server restart, which causes a bunch of issues. So to fix that, we need to ensure that the nodemon server only watches the server/ directory.

We can replace the dev:backend script in our package.json to the following:

"scripts": {
  // ...
  "dev:backend": "nodemon --watch server server/index.js",
  // ...
}

And then manually restart the server for nodemon to pick up on the change.

After all of that is done the web worker should work fine during development. For production, it will be compiled like any other JS asset and a minified copy of it will be inside the dist/ directory.

I've also created a add-webworker-support branch in this repo in case the steps above have any issue in them.

Please let me know if this works for your use case! Also let me know if you have any questions :)

@WRCIECH
Copy link
Author

WRCIECH commented May 7, 2023

Hey,

thanks for response. This solution worked (for wasm I just had to add ".wasm" extension to the list)! I close the issue.

BTW

There was a second issue that I also encountered with this approach in my project.
It was with using Cypress e2 and testing using dev (production worked fine)

The issue seems to be related to Cypress bug: cypress-io/cypress#26154
The solution is to switch from localhost:5173 to 127.0.01:5173 and adding in vite.config.js

  server: {
    host: '127.0.0.1',
    port: 5173
  },

@WRCIECH WRCIECH closed this as completed May 7, 2023
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