ctf0 / laravel-mix-versionhash

Auto append hash to file instead of using virtual one
MIT License
61 stars 18 forks source link

mix.combine() does not get version hash #10

Closed wolfgang42 closed 4 years ago

wolfgang42 commented 5 years ago

I'm using mix.combine() to concatenate some assets together that don't require any other processing. The resulting file is given a version id by mix.version(), but mix.versionHash() doesn't put a hash in the filename the way it does with .sass() or .js().

ctf0 commented 5 years ago

can u show me an example ?

wolfgang42 commented 5 years ago

Sure:

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

mix.combine([
    'resources/assets/js/raven.js',
    'resources/assets/js/matomo.js',
], 'public/assets/vendor.js');

mix.versionHash();

This just produces public/assets/vendor.js, with no hash. I expect it to be called vendor.0ddba11.js or so.

ctf0 commented 5 years ago

does it work correctly with mix.version() ?

wolfgang42 commented 5 years ago

Yes, with mix.version() I get /assets/vendor.js?id=adbb94909b3fc35d0fee.

ctf0 commented 5 years ago

@jellycode @Tlapi do u have any suggestions for this ?

wolfgang42 commented 4 years ago

This still seems to be happening with the latest version. Has there been any progress on investigating this?

ctf0 commented 4 years ago

i think with the latest changes from @Erutan409 🚀, it will be easier to fix it.

if you can plz give it a go maybe u can find a solution for it 👍

Erutan409 commented 4 years ago

Hmm... So, there's a little bit of an issue, here. Took me a while to track down what's happening, but here it goes:

  1. The intention is to load the plugin via the --config option with webpack, which points to this file.
  2. The compilation of the overall webpack file is derived from the .build() method, which adds the task that takes care of concatenation with .combine(), but is executed after loading the user's webpack.mix.json file.
  3. This plugin is using the chunkFilename, which means that the file from combine is not being hashed like the others are.

I even changed some of the code to be loaded as a Task that was added on the 'loading-plugins' event and confirmed that this plugin was executing its logic after all the other tasks that were previously loaded and executed. This didn't matter because of the aforementioned reliance on hashing from webpack, itself.

Uhm...I'm not sure how to proceed with this one. I mean - you could add your own arbitrary hash just to bust cache. But, that probably wouldn't be ideal. I'm guessing this is why laravel mix was initially designed to only suffix the filename with a query string since the combine is using concatenate.

I'm not intimately familiar with webpack as a whole, yet. So, I'm curious if these types of assets can be piped through it, using its hashing capabilities, like the codebase is already doing. Any ideas?

Erutan409 commented 4 years ago

I'll look more into this later.

ctf0 commented 4 years ago

@Erutan409 big thanx for ur time & hard work, if its too big of a deal we can ignore it for now until we have a better understanding of webpack

Erutan409 commented 4 years ago

How do you feel about crypto hashing and taking out the chunk hashing functionality in webpack?

It would make all hashing consistent.

ctf0 commented 4 years ago

i prefer to stick as close as possible to the webpack system, so its easier for maintainability or what do u think ?

Erutan409 commented 4 years ago

Well, crypto is part of node core. And after looking at gulp-rev, which I've used in other build scenarios, it eventually makes its way to crypto in order to hash the file names.

Arguably, this could be a much simpler solution for all cases.

ctf0 commented 4 years ago

okay then, lets go with it 👍

Erutan409 commented 4 years ago

@wolfgang42 Quick question for you:

For your use case, when you create a new file with combine from 2+ files, how are you including them into your app? Do you statically set a tag in the head tag or is your other JS functionality pulling it in dynamically?

Trying to get a better understanding of how this hashing should account for the various loaders restructuring import name change(s); if at all in this scenario.

If I was going to use the combine functionality, my first thought would be to assume that you wouldn't/couldn't anticipate the other generated asset(s) knowing how to include the aforementioned and I'd have to account for it myself.

ctf0 commented 4 years ago

i think what the combine does is it basically copy the content of first file to the next and save it into a new file.

now u either call it statically or use mix

wolfgang42 commented 4 years ago

@Erutan409

when you create a new file with combine from 2+ files, how are you including them into your app?

Just with a call to mix('/assets/vendor.js') in a static script tag. The reason I'm using combine() is because the app only needs a little bit of JS for a few things, so I'm using it as an extremely lightweight bundler that just joins together the JS files for each feature into a single file.

aschanMarcus commented 4 years ago

I also stumbled upon this issue and don't get any hashes with combine.

"laravel-mix": "^5.0.4",
"laravel-mix-versionhash": "^1.1.6",
mix.combine(['web/assets/css/_*.css'], 'web/assets/css/app.css')
mix.versionHash({length: 16})

It seems that proxyMethod.before(Mix, 'addTask', (task) => {}) isn't triggered. Looping through Mix.tasks seems to work.

ctf0 commented 4 years ago

@aschanMarcus can u send a PR with the fix ?

andresgutgon commented 3 years ago

@ahmedmaazin your fix looks good but with my configuration is not working:

const mix = require('laravel-mix');
const atImport = require('postcss-import');
const tailwindcss = require('tailwindcss');

mix
  .setPublicPath('./dist')
  .sass('assets/css/tailwindcss_utilities.scss', 'css')
  .sass('assets/css/blog.scss', 'css')
  .options({
    processCssUrls: false, // Put images in CSS relative to generated CSS
    postCss: [
      atImport(),
      tailwindcss('tailwind.config.js'),
      require('autoprefixer')
    ],
  })
  .js('assets/js/blog.js', 'js')
  .combine(
    [
      'dist/css/tailwindcss_utilities.css',
      'dist/css/blog.css'
    ],
    'dist/css/styles.css'
  )

if (mix.inProduction()) {
  require('laravel-mix-versionhash');
  // Cache busting only in production. Ex.: /css/blog-8e5c48eadbfdd5458ec6.js
  mix.versionHash()
}

So assets is empty []

image