Laravel-mix: Mix hot not working after upgrade from 1.7.2 to 2.0

Created on 25 Jan 2018  Â·  20Comments  Â·  Source: JeffreyWay/laravel-mix

Description:

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": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"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 --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": {
"axios": "^0.17.1",
"cross-env": "^5.1.3",
"drift-zoom": "^1.2.0",
"element-ui": "^2.0.11",
"font-awesome": "^4.7.0",
"js-cookie": "^2.2.0",
"laravel-mix": "^2.0.0",
"lodash": "^4.17.4",
"moment": "^2.20.1",
"moment-timezone": "^0.5.14",
"sweetalert2": "^7.6.3",
"v-debounce": "^0.1.2",
"vee-validate": "^2.0.3",
"vue": "^2.5.13",
},

Steps To Reproduce:

Before the update, run hot was working normally, but after updating to new version "2.0", run hot works, but the browsers nor the compiled files (from hot) don't reflect any change.

stale

Most helpful comment

I found a potential fix for this, it looks like removing the leading slash on entrypoints in the generated Webpack config fixes issues with HMR.

I would submit a PR with this but when I made these changes a bunch of tests started failing and I don't have enough time at the moment to look into the reasons why 😄

You can apply these changes in your node_modules/laravel-mix directory:

In src/builder/Entry.js: on line 90:

Change:

let name = output.pathFromPublic(Config.publicPath).replace(/\.js$/, '').replace(/\\/g, '/');

To:

let name = output.pathFromPublic(Config.publicPath).replace(/\.js$/, '').replace(/\\/g, '/').replace(/^\//, '');

This fixes issues with JS.

In src/builder/webpack-rules.js on line 137:

Change:

let outputPath = preprocessor.output.filePath.replace(Config.publicPath + path.sep, path.sep).replace(/\\/g,'/');

To:

let outputPath = preprocessor.output.filePath.replace(Config.publicPath + path.sep, path.sep).replace(/\\/g,'/').replace(/^\//, '');

This fixes issues with CSS.

All 20 comments

I have the same issue, also upgraded from 1.7.2 to 2.0.
I noted that If there are build files in the dist folder the dev-server serves them but they do not have HMR. If I delete the files int the dist folder then 404 errors appear.

+1

Downgraded from 2.0 to 1.7.x to resolve this.

I found a potential fix for this, it looks like removing the leading slash on entrypoints in the generated Webpack config fixes issues with HMR.

I would submit a PR with this but when I made these changes a bunch of tests started failing and I don't have enough time at the moment to look into the reasons why 😄

You can apply these changes in your node_modules/laravel-mix directory:

In src/builder/Entry.js: on line 90:

Change:

let name = output.pathFromPublic(Config.publicPath).replace(/\.js$/, '').replace(/\\/g, '/');

To:

let name = output.pathFromPublic(Config.publicPath).replace(/\.js$/, '').replace(/\\/g, '/').replace(/^\//, '');

This fixes issues with JS.

In src/builder/webpack-rules.js on line 137:

Change:

let outputPath = preprocessor.output.filePath.replace(Config.publicPath + path.sep, path.sep).replace(/\\/g,'/');

To:

let outputPath = preprocessor.output.filePath.replace(Config.publicPath + path.sep, path.sep).replace(/\\/g,'/').replace(/^\//, '');

This fixes issues with CSS.

@misenhower your fix worked;

I had same HRM not working issue with 2 almost identical projects;
The difference noticed comparing file by file was this version update -> slash handling

Thanks

is it happen in Laravel 5.5.33 or later?

I think……

https://github.com/JeffreyWay/laravel-mix/blob/049485f8d0f251355bd859b63cd9418b89f45755/src/index.js#L49-L56

Should be

        new File(path.join(Config.publicPath, 'hot')).write(
            http +
                '://' +
                Config.hmrOptions.host +
                ':' +
                Config.hmrOptions.port
        );

(I did not test it, but that may reason of double slash)

I created another workaround that doesn't modify the Laravel Mix code: https://github.com/JeffreyWay/laravel-mix/issues/1483#issuecomment-366685986

If you are getting no console output after enabling Hot Module Replacement, this comment fixes it.

If you are still getting "Cannot GET", it's because you're extracting vendor packages in your mix. So you will have to apply this workaround too:

In src/builder/Entry.js: on line 60:

let vendorPath = extraction.output
            ? new File(extraction.output)
                  .pathFromPublic(Config.publicPath)
                  .replace(/\.js$/, '')
                  .replace(/\\/g, '/')
            : path.join(this.base, 'vendor').replace(/\\/g, '/');

Replace it to this:

let vendorPath = extraction.output
            ? new File(extraction.output)
                  .pathFromPublic(Config.publicPath)
                  .replace(/\.js$/, '')
                  .replace(/\\/g, '/')
                  .replace(/^\//, '')
            : path.join(this.base, 'vendor').replace(/\\/g, '/');

Hey @misenhower, could you add a PR with your fixes?

@ItaloBC yes! that just nailed it

@misenhower

In src/builder/webpack-rules.js on line 137:

I'm using version ^2.1 and I could not find it ..maybe it's not needed ? I don't currently build any CSS.

@isometriq @misenhower

webpack-rules.js seems like a file that adds supports for loading html, images, fonts, etc, dynamically. The fix may be useful if you load these files and still they're not pushed into HMR. adding it afterwards the replacement lines.

                return (
                    Config.fileLoaderDirs.fonts +
                    '/vendor/' +
                    path
                        .replace(/\\/g, '/')
                        .replace(/^\//, '') // <-- Added this.
                        .replace(
                            /((.*(node_modules|bower_components))|fonts|font|assets)\//g,
                            ''
                        ) +
                    '?[hash]'
                );

@hinaloe

That fix should be correct. From my perspective, any path and url should start with / and end with a character. That way you ensure you can chain paths or urls.

If the path has ./, strip it to /. If it has double dots, leave it because it's traversing. Node().path should help a lot in these cases, i I would prefer passing everything to path instead of relying in regex.

If anyone is looking to use Laravel Mix and React HMR I've written up a little post on how I was able to get it working, it might help with this. I've also incorporated your solution here @ItaloBC , thanks!

https://medium.com/@grmcameron/laravel-mix-hot-module-reloading-with-react-966ade9ff244

@misenhower I don't see any line 137 on the webpack-rules.js file. I'm on 2.1 version of mix

Thanks @georgewritescode

With this now it works for me

Mix.listen('configReady', webpackConfig => {
    if (Mix.isUsing('hmr')) {
        // Remove leading '/' from entry keys
        webpackConfig.entry = Object.keys(webpackConfig.entry).reduce((entries, entry) => {
            entries[entry.replace(/^\//, '')] = webpackConfig.entry[entry];

            return entries;
        }, {});

        // Remove leading '/' from ExtractTextPlugin instances
        webpackConfig.plugins.forEach(plugin => {
            if (plugin.constructor.name === 'ExtractTextPlugin') {
                plugin.filename = plugin.filename.replace(/^\//, '');
            }
        });
    }
});

@Sylvert0 - Tried this fix but I'm getting:

mix.listen is not a function

Try a capital M. Mix.listen

@Sylvert0 solution dumps me errors in the console (not the str):

Uncaught TypeError: Cannot read property 'accept' of undefined
    at Object../node_modules/vue-loader/lib/template-compiler/index.js?{"id":"data-v-7ab29345","hasScoped":true,"buble":{"transforms":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./resources/assets/js/app.js 

Laravel 5.6 new package and same error

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

May I ask to reopen this issue? The problem still seems to be there, and the offered work around does not work with css and the extract plugin.

@Sylvert0 solution dumps me errors in the console (not the str):

Uncaught TypeError: Cannot read property 'accept' of undefined
    at Object../node_modules/vue-loader/lib/template-compiler/index.js?{"id":"data-v-7ab29345","hasScoped":true,"buble":{"transforms":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./resources/assets/js/app.js 

Encountering exactly this
issue occured since upstream upgraded to 3.0; for 2.1.11 I fixed it with

Mix.listen('configReady', (webpackConfig) => {
    if (Mix.isUsing('hmr')) {
        // Remove leading '/' from entry keys
        webpackConfig.entry = Object.keys(webpackConfig.entry)
            .reduce((entries, entry) => {
                console.log('entry', entry);
                entries[entry.replace(/^\//, '')] = webpackConfig.entry[entry];
                return entries;
            }, {});

        // Remove leading '/' from ExtractTextPlugin instances
        webpackConfig.plugins.forEach((plugin) => {
            if (plugin.constructor.name === 'ExtractTextPlugin') {
                console.log('plugin', plugin.filename);
                plugin.filename = plugin.filename.replace(/^\//, '');
            }
        });
    }
});

(can't recall where I found it exactly)
however this is causing weirdness on 3.0:
image
(Windows 10 pro)

@Sylvert0 solution dumps me errors in the console (not the str):

Uncaught TypeError: Cannot read property 'accept' of undefined
    at Object../node_modules/vue-loader/lib/template-compiler/index.js?{"id":"data-v-7ab29345","hasScoped":true,"buble":{"transforms":{}}}!./node_modules/vue-loader/lib/selector.js?type=template&index=0!./resources/assets/js/app.js 

Encountering exactly this
issue occured since upstream upgraded to 3.0; for 2.1.11 I fixed it with

Mix.listen('configReady', (webpackConfig) => {
    if (Mix.isUsing('hmr')) {
        // Remove leading '/' from entry keys
        webpackConfig.entry = Object.keys(webpackConfig.entry)
            .reduce((entries, entry) => {
                console.log('entry', entry);
                entries[entry.replace(/^\//, '')] = webpackConfig.entry[entry];
                return entries;
            }, {});

        // Remove leading '/' from ExtractTextPlugin instances
        webpackConfig.plugins.forEach((plugin) => {
            if (plugin.constructor.name === 'ExtractTextPlugin') {
                console.log('plugin', plugin.filename);
                plugin.filename = plugin.filename.replace(/^\//, '');
            }
        });
    }
});

(can't recall where I found it exactly)
however this is causing weirdness on 3.0:
image
(Windows 10 pro)

I have fixed the above by adding and checking the chunkNames for the CommonsChunkPlugin as well. Adding this below the ExtractTextPlugin check should fix it.

if (plugin.constructor.name === 'CommonsChunkPlugin') {
    plugin.chunkNames = plugin.chunkNames.map(name => {
        return name.replace(/^\//, '');
    });
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

stefensuhat picture stefensuhat  Â·  3Comments

jpmurray picture jpmurray  Â·  3Comments

pixieaka picture pixieaka  Â·  3Comments

amin101 picture amin101  Â·  3Comments

rderimay picture rderimay  Â·  3Comments