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

I encounter an unknown error when creating ParallelMeshBVHWorker in a Vite environment. #636

Closed
Innovgame opened this issue Feb 1, 2024 · 5 comments
Milestone

Comments

@Innovgame
Copy link
Contributor

Innovgame commented Feb 1, 2024

Describe the bug

When creating ParallelMeshBVHWorker in a Vite environment, I encountered an unknown error. Later, I found that the same error occurs with GenerateMeshBVHWorker. I investigated the issue and realized that it might be caused by the way the worker is created using new Worker( new URL( './generateMeshBVH.worker.js', import.meta.url ), { type: 'module' } ). So, I modified the code as shown below

	constructor( _worker ) {

		const worker = _worker || new Worker( new URL( './generateMeshBVH.worker.js', import.meta.url ), { type: 'module' } );
		super( worker );
		this.name = 'GenerateMeshBVHWorker';
	}

, and it started working fine. The worker is passed in from outside.

// import worker in vite
import generateMeshBVHWorker from "three-mesh-bvh/src/workers/generateMeshBVH.worker.js?worker";
const generator = new GenerateMeshBVHWorker(new generateMeshBVHWorker());

image

Code

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

import * as THREE from "three";
// @ts-ignore
import { ParallelMeshBVHWorker } from "three-mesh-bvh/src/workers/ParallelMeshBVHWorker.js";
const geometry = new THREE.BoxGeometry();
const worker = new ParallelMeshBVHWorker();
worker.generate(geometry).then((bvh: any) => {
  // geometry.boundsTree = bvh;
  debugger;
});
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

I wonder if it’s possible to add an optional worker parameter to the constructors of GenerateMeshBVHWorker and ParallelMeshBVHWorker to support it. Are there any alternative ways to resolve this issue in a Vite environment?

@Innovgame Innovgame added the bug Something isn't working label Feb 1, 2024
@gkjohnson gkjohnson removed the bug Something isn't working label Feb 1, 2024
@gkjohnson
Copy link
Owner

gkjohnson commented Feb 1, 2024

Hello! This syntax is the recommended way to create web workers in Vite. From the docs on web worker support:

image

Can you please confirm that this is not working and help understand what the issue is exactly if it's not?

@gkjohnson gkjohnson added this to the v0.7.2 milestone Feb 1, 2024
@Innovgame
Copy link
Contributor Author

I suspect the problem is caused by the Worker, but I’m not sure. I have created a reproducible example.
https://codesandbox.io/p/sandbox/dreamy-framework-prlcmc

image

@gkjohnson
Copy link
Owner

gkjohnson commented Feb 1, 2024

I have created a reproducible example.
https://codesandbox.io/p/sandbox/dreamy-framework-prlcmc

I think it would be best to make a simplified example that doesn't include any plugins like Vue so it's more clear that it's caused by the Worker and Vite. If it continues to happen I think this should be raised and reported as a bug to Vite before changes are made to this project. The Vite documentation states that it supports the syntax used in this project so it should be working.

@cxcorp
Copy link

cxcorp commented Jul 4, 2024

Just wanted to add some more context for anyone else landing on this via Google.

I think this is just that Vite has not implemented support for web workers in their "dependency pre-bundling" step, and the optimizer tries to optimize three-mesh-bvh. Apparently the dependency pre-bundler does not yet support all of their advertised features.

For this snippet:

import { GenerateMeshBVHWorker } from "three-mesh-bvh/src/workers/GenerateMeshBVHWorker.js";
const worker = new GenerateMeshBVHWorker();

and the most minimal Vite setup there can be, running vite to start the dev server and opening the page produces:

The file does not exist at "/home/user/example/node_modules/.vite/deps/generateMeshBVH.worker.js?worker_file&type=module" which is in the optimize deps directory. The dependency might be incompatible with the dep optimizer. Try adding it to optimizeDeps.exclude.

The worker is indeed missing from node_modules/.vite/deps and its _manifest.json.

The recommended solution in another Vite issue of excluding the files which load the .worker.js from the optimization seems to work fine enough for me:

// vite.config.js:
import { defineConfig } from "vite";

export default defineConfig({
  optimizeDeps: {
    exclude: [
      "three-mesh-bvh/src/workers/GenerateMeshBVHWorker.js",
      "three-mesh-bvh/src/workers/ParallelMeshBVHWorker.js",
    ],
  },
});

also exclude: ['three-mesh-bvh'] works.

This theory is supported by the fact that if I just copy the source of GenerateMeshBVHWorker.js to my project's own src/ and load the worker myself with Vite's ?worker syntax, it works:

import { WorkerBase } from "three-mesh-bvh/src/workers/utils/WorkerBase.js";
import generateMeshBVHWorker from "three-mesh-bvh/src/workers/generateMeshBVH.worker.js?worker";

export class GenerateMeshBVHWorker extends WorkerBase {
  constructor() {
    super(new generateMeshBVHWorker());
    this.name = "GenerateMeshBVHWorker";
  }
  // ...

So I agree with your conclusion - Vite issue.

Although, I also do think that being able to optionally inject the worker via the constructor could be nice. That way users can just refer to their toolchain's documentation on how to load workers.

P.S. Thanks so much for creating this package! I can't believe how fast raycasts are with a proper index.

@gkjohnson
Copy link
Owner

Although, I also do think that being able to optionally inject the worker via the constructor could be nice. That way users can just refer to their toolchain's documentation on how to load workers.

If there's a workaround in Vite right now I'd prefer to hold off on modifying APIs to accommodate bundler quirks. This is valid javascript and is something that works in Webpack 5 & Parcel - so as I see it this is something that should be fixed in bundlers. Though unfortunately Rollup & ESLint still don't have support, either (see rollup/rollup#3842, evanw/esbuild#312). If we see further complaints we can add the change if someone wants to make a PR with the constructor arguments .

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

3 participants