Laravel-mix: Need to run version() twice for images to be versioned after copied

Created on 15 Sep 2017  路  15Comments  路  Source: JeffreyWay/laravel-mix

  • Laravel Mix Version: #.#.# (1.4.2)
  • Node Version (v6.11.3):
  • NPM Version (3.10.10):
  • OS: Docker image based on php:7.1-fpm

Description:

Using the following webpack.mix.js:

mix.webpackConfig({
    plugins: [
        new webpack.ProvidePlugin({
            $: 'jquery',
            jQuery: 'jquery'
        })
    ]
})
    .setPublicPath('public')
    .sass('resources/assets/sass/app.scss', 'public/css')
    .js('resources/assets/js/app.js', 'public/js')
    .extract(['jquery'])
    .copy('resources/assets/images', 'public/images', false)
    .copy('resources/assets/favicons/*', 'public')
    .version('public/images');

The files copied into public/images are not being versioned.

During the first run of yarn run prod --non-interactive, the js, css, images referenced in css and the favicon are versioned.
The images are not versioned.

yarn run v1.0.2
$ npm run production "--non-interactive"

> @ production /var/www
> cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

 95% emitting DONE  Compiled successfully in 6186ms1:54:22 PM

                                                                         Asset       Size  Chunks             Chunk Names
        fonts/proximanova-regular-webfont.eot?469031e15d59bb85a6fc19097d6984ce    21.2 kB          [emitted]
        ....
        ....
        ....
                                                                    /js/app.js  396 bytes       0  [emitted]  /js/app
                                                                 /js/vendor.js      87 kB       1  [emitted]  /js/vendor
                                                               /js/manifest.js    1.38 kB       2  [emitted]  /js/manifest
                                                                  /css/app.css    19.1 kB       0  [emitted]  /js/app
                                                                  /favicon.png    1.66 kB          [emitted]

On the 2nd run, the images are now versioned.

yarn run v1.0.2
$ npm run production "--non-interactive"

> @ production /var/www
> cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

 95% emitting DONE  Compiled successfully in 5841ms1:54:31 PM

                                                                         Asset       Size  Chunks             Chunk Names
        fonts/proximanova-boldit-webfont.woff?df6755c672085f7e58fce60b2d4ff3b3      27 kB          [emitted]
        ...
        ...
        ...
                                                                    /js/app.js  396 bytes       0  [emitted]  /js/app
                                                                 /js/vendor.js      87 kB       1  [emitted]  /js/vendor
                                                               /js/manifest.js    1.38 kB       2  [emitted]  /js/manifest
                                                                  /css/app.css    19.1 kB       0  [emitted]  /js/app
                                                                  /favicon.png    1.66 kB          [emitted]
                                                   /images/social-facebook.svg  802 bytes          [emitted]
                                                   ...
                                                   ...
                                                   ...
                                                      /images/social-gplus.svg  914 bytes          [emitted]
                                                    /images/social-twitter.svg    1.17 kB          [emitted]
                                                       /images/usb-ed-logo.png    22.8 kB          [emitted]
stale

Most helpful comment

I believe the problem is only when versioning a directory. When versioning a directory, the glob() to get the files to version is run at the time the .version() method is called, not at the time the version task is actually run.

To work around this, we add in a new method at the top of our webpack.mix.js file:

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

mix.copyOutsideMixWorkflow = function (from, to) {
    new File(from).copyTo(new File(to).path());

    return this;
}.bind(mix);

Then, when copying directories, we use this new function instead of the .copy() function. For example:

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css')
    .copyOutsideMixWorkflow('resources/images', 'public/images')
    .copy('resources/favicons/favicon.ico', 'public/favicon.ico')
    .version([
        "public/images",
        "public/favicon.ico"
    ]);

Now, the .copyOutsideMixWorkflow() call will copy the files from 'resources/images' to 'public/images' immediately, so when the .version() method is called, those files will exist for the glob() call to pickup.

This works for us, but we don't have a fancy setup. I don't know what potential complications this has, but it works if you're just using npm run dev and npm run prod.

All 15 comments

+1

Laravel Mix Version: 1.6.1
Node Version: v8.9.1
NPM Version: 5.5.1
OS: Ubuntu 16.04.3 (Linux Subsystem on Windows 10)

Same here

This is related to https://github.com/JeffreyWay/laravel-mix/issues/1257

The tasks run asynchronously, therefore at the time the files are versioned, they don't actually exist in the directory (where they've been copied to).

My work-around was to manually add all the files to an array.

let glob = require('glob');

let dirs = [
    {
        source: 'resources/assets/images',
        dest: 'public/images',
    },
];

// .... rest of mix instructions are here...

dirs.forEach((dir) => {
    mix.copy(dir.source, dir.dest, false);
});

let files = [];
dirs.forEach((dir) => {
    glob.sync('**/*', { cwd: dir.source }).forEach((file) => {
        files.push(dir.dest + '/' + file);
    });
});

mix.version(files);

The previous solution I tried didn't work consistently as there's still guarantee in the order which the tasks (copy vs version) will execute.

Same issue here. I thought I was going crazy....

This is still happening. Any solution? I have to run the command twice to get it working... :disappointed:

I'm getting this too. In my case it was a little different:

We clear out the public directory first so we don't deploy the assets that were built in it during development. Since public directory is mostly .gitignored, we need to refresh for production during deploy.

rm -rf public/*
NODE_ENV=production yarn run webpack --progress --hide-modules --color --config=node_modules/laravel-mix/setup/webpack.config.js

And then my webpack.mix.js file had

mix.copyDirectory("src/assets/images", "public/images");
mix.js("src/assets/js/app.js", "public/js");
mix.sass("src/assets/css/app.scss", "public/css/app.css");
mix.setPublicPath("public");
mix.version(["public/images"]);

This would have the js and css in the mix-manifest, but no images. If I stopped doing the rm -rf before, then it would be fine, OR running version() twice would work.

And actually, the only reason I'm running in to this is because I have to do extra processing to NOT have query cache, and use filename hashing instead.

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.

Well, we got no workaround and not even an acknoledgement answer from the maintainer...
Is there even interest into fixing this?

My personal work-around here is to keep my images in public/images/ in repo. I .gitignore all other build files in public/ except for images.

I believe the problem is only when versioning a directory. When versioning a directory, the glob() to get the files to version is run at the time the .version() method is called, not at the time the version task is actually run.

To work around this, we add in a new method at the top of our webpack.mix.js file:

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

mix.copyOutsideMixWorkflow = function (from, to) {
    new File(from).copyTo(new File(to).path());

    return this;
}.bind(mix);

Then, when copying directories, we use this new function instead of the .copy() function. For example:

mix.js('resources/js/app.js', 'public/js')
    .sass('resources/sass/app.scss', 'public/css')
    .copyOutsideMixWorkflow('resources/images', 'public/images')
    .copy('resources/favicons/favicon.ico', 'public/favicon.ico')
    .version([
        "public/images",
        "public/favicon.ico"
    ]);

Now, the .copyOutsideMixWorkflow() call will copy the files from 'resources/images' to 'public/images' immediately, so when the .version() method is called, those files will exist for the glob() call to pickup.

This works for us, but we don't have a fancy setup. I don't know what potential complications this has, but it works if you're just using npm run dev and npm run prod.

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.

I am encountering this issue with laravel-mix 4.1.2, using copyDirectory('resources/images', 'public/images').
I tried to replace this call by copy('resources/images/', 'public/images) for example and it does no work either.
The only working solution is currently the one @patrickcarlohickman has suggested.

Is there any official fix for this issue?

I started a new project, copied webpack config from previous one (and using same 6.0.6 version of mix) and found out copied images are not being added to mix manifest, while in previous project, while using the very same command, they did. Strange indeed.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jpmurray picture jpmurray  路  3Comments

amin101 picture amin101  路  3Comments

hasnatbabur picture hasnatbabur  路  3Comments

mstralka picture mstralka  路  3Comments

kpilard picture kpilard  路  3Comments