jelledv4's avatar

Laravel Vite importing Web Workers with HMR - CORS origin error

Hey, I'm using Laravel Vite, and am trying to import a Web Worker. My Laravel dev site runs locally on {project}.test, and Vite runs on 127.0.0.1:5173

While Hot Module Replacement works well, when importing a web worker (in the way explained here https://vitejs.dev/guide/features.html#web-workers ), the browser throws an Origin error, because my browser tries to import the web worker from 127.0.0.1:5173, while the website runs on {project}.test

Screenshot: https://i.imgur.com/z3NUuze.png

Weirdly enough my browser loads all Vite assets just fine, it only doesn't work when it tries to import the web worker from the JavaScript files served by Vite.

The web workers do get loaded when I run vite build or vite watch, because at that moment they get served from the 'build' directory in my Laravel project.

Does anyone have an idea on how to import web workers when using hot module reloading in Vite?

1 like
10 replies
LaryAI's avatar
Level 58

It sounds like you are running into a CORS issue. You can try adding a Access-Control-Allow-Origin header to the response from 127.0.0.1:5173 to allow requests from {project}.test.

You can do this by adding the following code to your vite.config.js file:

module.exports = {
  server: {
    headers: {
      'Access-Control-Allow-Origin': '{project}.test'
    }
  }
}

This should allow requests from {project}.test to 127.0.0.1:5173 and should resolve the CORS issue.

jelledv4's avatar

@LaryAI Hey AI Lary, that unfortunately does not work. I tried it, but the thing is my browser does load the scripts and other Vite assets just fine, it's only the web worker (that get's loaded from a JS file served by Vite's dev server on 127.0.0.1:5137). Adding Access-Control-Allow-Origin does indeed add the header, but it still results in the same error when it tries to import the Web Worker.

I also tried 'Access-Control-Allow-Origin': '*',, but it doesn't have an effect. And the browser loads all other assets just fine, as said before. It's only the web worker in HMR/dev server mode.

Daniesy's avatar

The issue is caused by the fact that workers need to be loaded from the same domain and port. I have the same issue. Looking for a solution. Something like this could work but it’s not that elegant

self.MonacoEnvironment = {
    getWorkerUrl: function (moduleId, label) {
        if (label === 'typescript' || label === 'javascript') {
	    return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
	        importScripts('${process.env.ASSET_PATH}/typescript.worker.js');`
	    )}`;
        }

	return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
	    importScripts('${process.env.ASSET_PATH}/editor.worker.js');`
	)}`;
    }
}

Daniesy's avatar

I managed to hack my way trough. I'm running Valet and the website is configured to run under the domain templates.test.

Step 1:

Add origin to the vite-config.js:

{
	...
    server: {
        ...
        hmr: {host},  
        origin: `https://${host}`,  // in my case it's https://templates.test
    }
}

After adding origin, all workers urls will be pointing to the laravel server, instead of the Vite one. Instead of https://domain:5174/node_modules/... you'll have https://domain/node_modules/...

Step 2:

In your web.php file, add this route:

if (env('ENVIRONMENT') != "production") {
    // Match all routes that start with node_modules (from Vite)
    Route::get('/node_modules/{any}', function ($any) {
		// Disable ssl checks for php
        $streamContext = stream_context_create([
            "ssl" => [
                "verify_peer" => false,
                "verify_peer_name" => false,
            ],
        ]);
       
       // Fetch the Vite compiled worker module and return it
        return response(file_get_contents(config('app.url').":5174/node_modules/$any", false, $streamContext), 200)
            ->header("Content-Type", "text/javascript");
    })->where('any', '(.*)');
}
UhOh's avatar

@jelledv4 @daniesy want to say thanks, cuz it's like nobody is using Web Workers, nobody really has an answer. So I'll update this post as I can. For now, the following will stop the CORS issue. Stack is L10+Inertia+Vue+Vite.

Adding this config to Vite was key to stopping the CORS issue. The worker.js file however doesn't execute when the Vite is running. If you kill Vite, the web worker works 100%...(Need to run npm run build for the web worker to get packaged and work). Not sure what else is needed to make it run with Vite dev running. But at least should run in production.

// vite.config.js
    server: {
        hmr: 'localhost', // set to whatever your host is
        origin: 'http://localhost',  // set to whatever your host is
    },
Barbapapazes's avatar

@UhOh It does not work because both the protocol, the host and the port must be the same to have the same origin.

CalElAn's avatar

Hi, facing the same issue here. The web worker works when I run "npm run build" or when I kill vite when it's running the dev server. When vite is running I get the same error: "DOMException: Failed to construct 'SharedWorker': Script at 'http://localhost:5181/node_modules/.vite/deps/HierarchicalLayout.worker.js?worker_file&type=module' cannot be accessed from origin 'http://localhost:15000'"

Were you able to find a solution?

wrangelvid's avatar

I am also facing the same issue with the Vite dev server. @calelan, did you end up finding a solution? I’ve tried (still am) a few things:

  • Allowing any origin through permissive CORS headers in Laravel seemed to be disregarded by the browser when it comes to workers.
  • I considered bundling the worker files separately under a build/worker directory while running Vite build watch on the worker files and Vite dev on the rest. This is still in progress.
  • Another idea involved setting up Nginx with proxies so that the Laravel app and the Vite dev server share the same origin. However, my configurations aren’t quite right, which is why I’m still getting the same CORS issues.

I'll try to update here once I find something, but nothing trivial appeared to me so far.

iEgria's avatar

try add in vite.config.js solve for me

server: {
    cors: {
        origin: 'your-apps.test'
    },
},

Please or to participate in this conversation.