laravel-mix / laravel-mix

The power of webpack, distilled for the rest of us.
MIT License
5.25k stars 808 forks source link

make Version() work on combine() and copy() plz #270

Closed reno1979 closed 7 years ago

reno1979 commented 7 years ago

Related to: https://github.com/JeffreyWay/laravel-mix/issues/53 https://github.com/JeffreyWay/laravel-mix/issues/154 https://github.com/JeffreyWay/laravel-mix/issues/163 https://github.com/JeffreyWay/laravel-mix/issues/211

@JeffreyWay Perhaps you will consider a possible fix or workaround for this.

We combine a bunch of vendor files (allready minified etc) , but sometimes we want to change the content and make sure the visitors get the updated combined file, the version() helper would be very important for us here.

hovsep commented 7 years ago

"minify" and other transformers not work on collections after copy\combine etc

huglester commented 7 years ago

hello,

this one would be lovely. Because even first combining and trying to version combined files does not work...

mix.combine([
    'addons/default/webas/default-theme/resources/vendor/js/vendor/jquery.min.js',
    'addons/default/webas/default-theme/resources/vendor/js/vendor/what-input.min.js',
    'addons/default/webas/default-theme/resources/vendor/js/foundation.min.js',
    'addons/default/webas/default-theme/resources/vendor/js/motion-ui.min.js',
    'addons/default/webas/default-theme/resources/vendor/js/blueimp-gallery.min.js',
    'bower_components/typeahead.js/dist/typeahead.bundle.js',
    'bower_components/handlebars/handlebars.js',
    'addons/default/webas/default-theme/resources/js/typeahead.js',
], 'public/assets/js/app.js');

mix.js('public/assets/js/app.js', 'public/assets/build/js/app.js')
    .version();
npm ERR! Darwin 16.4.0
npm ERR! argv "/usr/local/Cellar/node/7.5.0/bin/node" "/usr/local/bin/npm" "run" "dev"
npm ERR! node v7.5.0
npm ERR! npm  v4.1.2
npm ERR! code ELIFECYCLE
npm ERR! @ dev: `node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js`
npm ERR! Exit status 2
npm ERR!
npm ERR! Failed at the @ dev script 'node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the  package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR!     node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js
npm ERR! You can get information on how to open an issue for this project with:
npm ERR!     npm bugs
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!     npm owner ls
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
JeffreyWay commented 7 years ago

That error you're seeing is unrelated to the order.

Think of mix.combine() as combining a bunch of files into one. It has nothing to do with your Webpack compile process. It's just a helpful step that will be performed after Webpack compiles. That's why it doesn't get versioned. It was never part of your Webpack entry to begin with.

QWp6t commented 7 years ago

The tl;dr of it is that you'd do all of the combine() (and copy()) logic during emit and append to compilation.assets with a key matching the destination file name. It looks something like this:

          compilation.assets[fileDestinationPath] = {
            size: () => fileStats.size,
            source: () => fileContent
          };

Then do your version() logic during after-emit (or emit, but then order matters; you'd have to make sure it runs after combine()) and iterate over compilation assets, versioning each one as you go along. Write before/after file names to your manifest object.

It's possible I missed something, but that's more or less what I'm doing in a shitty plugin that I wrote for copying assets (because copy-webpack-plugin has terrible manifest support).

JeffreyWay commented 7 years ago

If someone wants to submit a PR and add support for that, I'm all for it.

JeffreyWay commented 7 years ago

This is done for mix.combine() now. We still don't version copied files, but you can manually do so with mix.version(['path/to/file.js']);

jochantrelle commented 7 years ago

How is this closed, where is the answer. mix.version does not work manually, at all!

I've tried: -1 mix.js([ 'resources/assets/js/app.js', 'resources/assets/js/vendor/gsap/TweenMax.min.js', 'resources/assets/js/vendor/gsap/utils/SplitText.min.js', 'resources/assets/js/cems/RedGoldGreen-Accenter.js' ], 'public/js') .sass('resources/assets/sass/app.scss', '../resources/assets/css/compiledsass.css') .combine([ 'resources/assets/css/compiledsass.css', 'resources/assets/css/fonts/glyphicons.css', 'resources/assets/css/fonts/king.css' ], 'public/css/app.css') .sourceMaps(); .version();

--2 mix.js([ 'resources/assets/js/app.js', 'resources/assets/js/vendor/gsap/TweenMax.min.js', 'resources/assets/js/vendor/gsap/utils/SplitText.min.js', 'resources/assets/js/cems/RedGoldGreen-Accenter.js' ], 'public/js');

mix.sass('resources/assets/sass/app.scss', '../resources/assets/css/compiledsass.css');

mix.combine([ 'resources/assets/css/compiledsass.css', 'resources/assets/css/fonts/glyphicons.css', 'resources/assets/css/fonts/king.css' ], 'public/css/app.css').version('public/css/app.css');

mix.sourceMaps();

mix.version(['public/js/app.js', 'public/css/app.css']);

---3 mix.sass('resources/assets/sass/app.scss', '../resources/assets/css/compiledsass.css');

mix.combine([ 'resources/assets/css/compiledsass.css', 'resources/assets/css/fonts/glyphicons.css', 'resources/assets/css/fonts/king.css' ], 'public/css/app.css').version('public/css/app.css');

ALL WITH THE SAME END RESULT: 'public/js/app.****.js' created, perfect! 'public/css/app.css' not versioned WTF! Note in my mix.sass i have to climb the directory tree '../' else i get output in the 'public' folder.

I don't care to know the semantics about the web pack build process, I just want this to work nice and smooth like elixir did, I don't want to be concerned with all this other jargon, I've got enough to think about. I want to combine my css and my compiled sass and version the output, why is this not straight forward?

The .js is, I say mix.js list my array of files to concat/cxombine it does it, I say version and it's versioned, why not the same with css?

I change css heavily during development as I do .js so why assume "we still don't version copied files" why assume what I want to version, if I want to version a .png it's my prerogative, its not a patch that someone needs to do its a given!

Feeling my frustration? HELP! PLEASE! anyone!

jochantrelle commented 7 years ago

PS. I see the ';' in some inappropriate places above, a result of coping my code from Sublime and rebuilding the three version in this text area. Trust me the statements/expressions are in correct syntax in live code.

jochantrelle commented 7 years ago

Hey, going thru Laravel Docs... 5.4... Whats up here guys

TypeError: mix.styles is not a function!

JeffreyWay commented 7 years ago

@jochantrelle Upgrade to the latest version of Mix. You have an old version.

jochantrelle commented 7 years ago

@JeffreyWay humbled by a direct response from you sir, many thanks.

However, I've now dug myself deeper into despair. I did 'npm update' thinking I'd update mix. I got 'vue@2.2.1' updated only. Which sparked a 'vue-template-compiler' version mismatch. Deleted my node_modules folder so as to go-again, did 'npm install' now when I run my watch I'm at the "I'm a dummy error epistle"

node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js

sh: node_modules/cross-env/bin/cross-env.js: No such file or directory

npm ERR! Darwin 16.4.0 nom ERRors!.... for days... ...

About to call it day and roll back to my Laravel 5.0 dev env and wait a few months to start using Vue and L5.4+ and the all this good stuff when its all running smoothly... :( may as well head to the beach to find peace of mind. This is too simple a step to be stressing me like this... I must be missing something.

devcircus commented 7 years ago

That last error has been brought up probably 20 times here. Cross-env made some changes and it caused problems. Check through the issues and you'll find the solution. I think basically you can pull the latest package.json from the laravel github repo and nuke your node_modules before running npm install, but you may want to check to be sure that covers it. You're missing out if you revert. Hang in there.

jochantrelle commented 7 years ago

@devcircus LIFE SAVER!

You have no idea. That did it. With all this to take in completely forgot about Laravel's GitHub repo!

If you can make it to Miami in April and need tickets to Kaya Fest I got you!

Much Appreciated!

jvrsolis commented 7 years ago

@reno1979 for your issue with copying and versioning remember you are still in a node javascript environment just download a helper(glob-fs) to do the task of obtaining all your files in the copy destination directory and save it to a variable and run mix.version on that variable. At least this way you don't have a long array list and still accomplish what you want with the flexibility of deciding which type of files to version using glob:

npm install glob-fs --save-dev npm install glob-fs-dotfiles --save-dev //middleware for filtering only files var dotfiles = require('glob-fs-dotfiles'); var glob = require('glob-fs')({}).use(dotfiles());

mix.copy('public/src/src', 'public/dist/dest'); var files = glob.readdirSync('public/dist/*/.ext'); mix.version(files);

On a side note if you guys find yourself having a long array of directories or file paths for any laravel mix task that may not support glob parameters but supports arrays like mix.version just use the same trick above to keep your web pack.mix file cleaner. For those still using elixir like I am since I have had the privilege of inheriting a 5.2 frontend designed horribly you can still use this as approach as well there.

mxl commented 6 years ago

@Javier-Solis Your example will not work because mix executes tasks asynchronously and when you call var files = glob.readdirSync('public/dist/**/*.ext'); files in public/dist do not exist yet. Also I recommend to us node-glob package which is already used by laravel-mix so you do not need to install extra dependency.

In my case I have various assets in resources directory so directory tree looks like:

- resources
  | - css
  | - fonts
  | - images
  | - js
  | - less

I need to copy to public and version all these directories except less which I need to preprocess and also version.

My webpack.mix.js looks like:

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

mix.disableNotifications();

const
    directoriesToCopy = ['css', 'fonts', 'images', 'js'],
    publicDir = 'public/',
    publicCssDir = publicDir + 'css/',
    resourcesDir = 'resources/',
    resourcesLessDir = resourcesDir + 'less/',
    lessFiles = glob.sync('**/*.less', {cwd: resourcesLessDir});

directoriesToCopy.forEach(d => mix.copyDirectory(resourcesDir + d, publicDir + d));

lessFiles.forEach(f => mix.less(resourcesLessDir + f, publicCssDir + f.slice(0, -'less'.length) + 'css'));

mix.version([].concat(...directoriesToCopy.map(d => glob.sync('**/*', {cwd: resourcesDir + d}).map(f => d + '/' + f))).map(f => publicDir + f));

Basically I use glob to recursively get a list of all files in each copied directory, replace resources with public in their paths and then pass list of all such files to mix.version.