I'm developing a Laravel app that runs inside an iFrame. While everything works fine with production builds (npm run build), I'm unable to get Vite working in development mode, which makes the development workflow very cumbersome.
I am developing for a web-application which has an app-store, where "apps" are actually just iframes who get passed certain query params.
Current Setup:
# Terminal 1
php artisan serve
# Terminal 2
npm run dev
# Terminal 3
ngrok http 8000
The Issue:
When accessing the ngrok URL directly in the browser, everything works perfectly. However, when the app is loaded through the iFrame, I get CORS and mixed content errors:
Access to script at 'http://[::1]:5173/@vite/client' from origin 'https://<ngrok-url>.eu.ngrok.io'
has been blocked by CORS policy: Permission was denied for this request to access the `unknown` address space.
GET http://[::1]:5173/@vite/client net::ERR_FAILED
Access to script at 'http://[::1]:5173/resources/js/app.ts' from origin 'https://<ngrok-url>.eu.ngrok.io'
has been blocked by CORS policy: Permission was denied for this request to access the `unknown` address space.
Mixed Content: The page at 'https://<parent-web-url>/' was loaded over HTTPS, but requested an
insecure script 'http://0.0.0.0:5173/resources/js/app.ts'. This request has been blocked;
the content must be served over HTTPS.
What I've Tried:
Basic HTTPS with mkcert
Created local certificates: mkcert localhost.
Updated vite.config.ts to include the certificates:
server: {
https: {
key: fs.readFileSync(path.resolve(__dirname, "localhost-key.pem")),
cert: fs.readFileSync(path.resolve(__dirname, "localhost.pem"))
},
host: '0.0.0.0'
}
Result: Got ERR_BLOCKED_BY_CLIENT errors because browser was trying to load from https://0.0.0.0:5173
Laravel proxy for Vite:
Added proxy route in routes/web.php:
Route::any('{vite_path}', function ($vite_path) {
// Proxy logic to forward requests to https://localhost:5173
})->where('vite_path', '.*');
Result: Getting 404 errors for certain Vite internal modules:
GET https://<ngrok-url>.eu.ngrok.io/node_modules/vite/dist/client/env.mjs net::ERR_ABORTED 404
GET https://<ngrok-url>.eu.ngrok.io/@id/__x00__plugin-vue:export-helper net::ERR_ABORTED 404
How can I configure Laravel and Vite to work together with HMR?
npm run build works perfectly, but this of course removes HMR.I found the solution myself!
To get HMR working I had to tunnel both the Laravel server and the Vite dev server through ngrok.
So I added a VITE_DEV_SERVER_URL to my .env file:
VITE_DEV_SERVER_URL=vite-<your-domain>.eu.ngrok.io
Next I configured ngrok to handle two tunnels, ngrok.yml:
tunnels:
laravel:
proto: http
addr: 8000
hostname: your-domain.eu.ngrok.io
vite:
proto: http
addr: 5173
hostname: vite-your-domain.eu.ngrok.io
I then updated vite.config:
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd());
return {
server:
process.env.NODE_ENV === "development"
? {
host: "0.0.0.0",
strictPort: true,
hmr: {
// The browser inside the iframe will connect to this URL for HMR updates.
host: env.VITE_DEV_SERVER_URL,
protocol: "wss", sites
clientPort: 443
}
}
: {},
...rest of config
};
});
This way everything works!