3

Am running Laravel Valet to host sites locally, and Laravel Mix to compile the assets and perform HMR using Webpack dev server

I secured the .dev site locally by

valet secure

No problem calling {{ mix('js/app.js') }} when running npm run watch

But whenever I want to take advantage of hot reloading by running the hot npm script, I get this

GET https://localhost:8080//css/app.css net::ERR_CERT_AUTHORITY_INVALID

GitHub issues suggested to add --https flag, I tried it and also --http

I even disabled host checks by --disable-host-check flag and cleared every possible cache and even tried a fresh git clone but to no avail

Here's my package.json

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --https --disable-host-check --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "@kazupon/vue-i18n-loader": "^0.3.0",
        "cross-env": "^5.1",
        "eslint-plugin-vue": "^5.2.3",
        "laravel-mix": "^4.0.7",
        "resolve-url-loader": "^2.3.1",
        "sass": "^1.21.0",
        "sass-loader": "^7.1.0",
        "vue-template-compiler": "^2.6.10"
    },
    "dependencies": {
        "algoliasearch": "^3.33.0",
        "axios": "^0.19.0",
        "font-awesome": "^4.7.0",
        "jquery": "^2.1.1",
        "lato-webfont": "^2.15.1",
        "modernizr": "^3.7.1",
        "raleway-webfont": "^3.0.1",
        "raphael": "^2.1.4",
        "vlightbox": "^2.0.2",
        "vue": "^2.5.17",
        "vue-i18n": "^8.12.0",
        "vue-instantsearch": "^2.2.1"
    }
}

and webpack.mix.js if it's helpful

const mix = require('laravel-mix');

// Extend Mix with the "i18n" method, that loads the vue-i18n-loader
mix.extend('i18n', new class {
    webpackRules() {
        return [{
            resourceQuery: /blockType=i18n/,
            type: 'javascript/auto',
            loader: '@kazupon/vue-i18n-loader',
        }, ];
    }
}(), );

// Call the .i18n() (to load the loader) before .js(..., ...)
mix.i18n()
   .js('resources/js/app.js', 'public/js')
   .sass('resources/sass/app.scss', 'public/css');

What am I doing wrong? Can this be reproduced? should I find a way to secure localhost:8080 too?

Salim Djerbouh
  • 10,719
  • 6
  • 29
  • 61

3 Answers3

7

So to get this working, instruct laravel mix to use specific domain and port for HMR in the options object

webpack.mix.js

// Get the APP_URL from .env and remove protocol
let url = process.env.APP_URL.replace(/(^\w+:|^)\/\//, '');
mix.options({
   hmrOptions: {
       host: url,
       port: 8080 // Can't use 443 here because address already in use
   }
});

Keep the --https flag to instruct webpack-dev-server as to what protocol to use, however, remove --disable-host-check because it's redundant (Google Chrome has a strict HSTS policy for .dev domains anyway)

Now given that valet secure generates SSL key and certificate for each domain, instruct webpack-dev-server to use them as well in the hot script of package.json

"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js
--inline --hot --https
--key /home/caddy/.valet/Certificates/laravel.dev.key
--cert /home/caddy/.valet/Certificates/laravel.dev.crt --config=node_modules/laravel-mix/setup/webpack.config.js",

replace /home/caddy/ by your own absolute path

run

npm run hot

Now hot reloading is working fine with secured valet sites

Source

Salim Djerbouh
  • 10,719
  • 6
  • 29
  • 61
2

Had issues as of mix6. Here are the full steps to get it working in a fresh project.

  • Add the domain to your .env
APP_DOMAIN=example-app.test

Replace your scripts in package.json

    "scripts": {
        "dev": "npm run development",
        "development": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot --https",
        "prod": "npm run production",
        "production": "mix --production"
    },

Edit your webpack.mix.js

const mix = require('laravel-mix');
const fs = require("fs");
const path = require("path");

const homeDir = process.env.HOME;
const host = process.env.APP_DOMAIN

mix
    .options({
        devServer: {
            https: {
                key: fs.readFileSync(path.resolve(homeDir, `.config/valet/Certificates/${host}.key`)).toString(),
                cert: fs.readFileSync(path.resolve(homeDir, `.config/valet/Certificates/${host}.crt`)).toString(),
                ca: fs.readFileSync(path.resolve(homeDir, `.config/valet/CA/LaravelValetCaSelfSigned.pem`)).toString(),
            },
        },
        hmrOptions: {
            host: host,
            port: 8080
        }
    })
    .js('resources/js/app.js', 'public/js')

Add the mixed JS to a blade view, plus a meta tag to automatically upgrade http requests to https

    <head>
      <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
        ...
    </head>
    <body class="antialiased">
        <div id="app"></div>
        <script src="{{ mix('js/app.js') }}"></script>
    </body>

Go to that blade view, open your browser's console, the app.js should STILL BE SSL erroring. Manually "open file in new tab", you should be taken to something like https://example-app.test:8080/js/app.js. Chrome will warn, you can accept the risk.

THEN go back to your regular view.

Things work.

JasonHorsleyTech
  • 392
  • 1
  • 5
  • 11
0

Simply add the --https flag to your "hot" npm script. As long as you have a valid certificate for your Laravel backend in place, you should be good to go. Webpack dev server takes care of the certificate generation for its server.

"scripts": {
    "hot": "mix watch --hot --https",
    ...
},
Ali Bakhshandeh
  • 433
  • 6
  • 10