ardf16's avatar

Laravel-mix impossible to extract lodash modules

Hi, when using basic laravel mix configuration i'm trying to extract single lodash modules imported like:

import debounce from 'lodash/debounce'
import mergeWith from 'lodash/mergeWith'
// ... etc

so when the extract is specific like:

mix.extract(['lodash/debounce', 'lodash/mergeWith']);

what the mix actually does is it puts the lodash modules both to app.js and vendor.js.

So the other approach would be:

mix.exctract(['lodash']);

Then mix give no lodash in app.js but WHOLE lodash.js in vendor plus the modules used in app (aside of lodash.js code)

Tried whole bunch of configurations and still have failed to successfully export just required modules to vendor.js.

0 likes
8 replies
ardf16's avatar

Thanks @sti3bas for looking into my post.

You're right. Using lodash.module allowed me to move all modules to vendor. The problem is that now all imported modules got havy compared to previous results. All lodash.module combined are over 100k which is a lot compared with ~40k using lodash/module approach. Downside is i cant extract it to vendor but it's still over 60k less.

To be clear the

mix.extract(['lodash/debounce', 'lodash/mergeWith']);

approach did extract only required modules to vendor (not whole lodash.js) but failed to remove them from app.js

So this is an issue of removing the packages extracted to vendor.js from the app.js

Sti3bas's avatar

@ardf16 works fine in a fresh Laravel app. Both packages are extracted to vendor.js which size is 11.4 Kib and it's removed from app.js. The problem might be related to other packages which requires the whole lodash package.

ardf16's avatar

Hi i think i'm getting somewhere. @sti3bas - as you did i started fresh and narrowed down to most basic scenario and i have example of what i try to do and maybe someone will explain why it fails:

// app.js ==========================

import debounce from 'lodash/debounce';
import isArray from 'lodash/isArray';
import differenceBy from 'lodash/differenceBy';

// webpack.mix.js ==================
require('laravel-mix-bundle-analyzer');


let lodash = [
	'lodash/debounce',
	'lodash/isArray',
	'lodash/differenceBy'
];

// mix.js('resources/js/app.js', 'public/js').extract(); // the propper result
mix.js('resources/js/app.js', 'public/js').extract([...lodash], 'public/js/vendor'); // wtf ?

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

mix.bundleAnalyzer({
  analyzerMode: 'static'
});

So the propper result gives vendor with only used lodash modules. But when i go specific on the modules i get crazy results like some lodash modules on vendor.js some on app.js and i just cant simply wrap my head around why is this the case. I want to be specific with this modules - this is required for the next step wchich is unrelated to this issue;

update When you use specific lodsh module exports in bundle analyser you can see its both in vendor.js and in app.js. But the vendor copy has node_modules/lodash in package name... Maybe it say something to someone

Sti3bas's avatar

@ardf16 the above config includes full lodash package in both app.js and vendor.js in a fresh Laravel 7 app.

After running npm uninstall lodash then npm install lodash.debounce lodash.isarray lodash.differenceby and changing slash version (lodash/debounce) to dot version (lodash.debounce), only these three modules are included in vendor.js file and no lodash modules are included in app.js.

ardf16's avatar

Hi, i get the workaround but a huge drawback is size of bundle and i'm looking for solution.

['lodash.meanby',  'lodash.clonedeep',  'lodash.minby',  'lodash.maxby',  'lodash.find',  'lodash.filter',  'lodash.take',  'lodash.drop',  'lodash.findindex',  'lodash.map',  'lodash.debounce',  'lodash.ismatch',  'lodash.reduce',  'lodash.remove',  'lodash.clone',  'lodash.groupby',  'lodash.orderby',  'lodash.differenceby',  'lodash.compact',  'lodash.uniq',  'lodash.sortby',  'lodash.first',  'lodash.last',  'lodash.merge',  'lodash.concat',  'lodash.includes',  'lodash.pick',  'lodash.throttle',  'lodash.mergewith' ]
  • @sti3bas - your suggestion produces: /js/vendor.js 215 KiB
  • regular .export() with no specific extract packages gives: /js/vendor.js 38.7 KiB and extracts all from app.js
  • export with packages parts specified also: /js/vendor.js 38.7 KiB but it for some wierd reason also leaves this in app.js which is also 38KiB

so the question is why it fails to extract specific parts of lodash package? Is this a bug? I mean - when you use only part of pacgake trough import statement within your app and mix.export() with no params you get what you expect, but when extracting specific package parts it fails to extract them properly.

ardf16's avatar

Ok, when you let just webpack do the job with:

mix.webpackConfig({
	optimization: {
    	splitChunks: {
			cacheGroups: {
		        commons: {
		          name: 'js/vendor',
		          chunks: 'initial'
	        	}
  			}
    	}
  	}
})

you get what you expect. So i think it might be bug but still, need to learn whole bunch of webpack and deep dive into mix in order to figure that out :/.

ardf16's avatar

Well diving into Extract module from laravel-mix didnt gave me any answers. Somehow extracting with mix.webpackConfig gives different results then using mix.extract. This is suprising because underlying code is exacly the same. I reported it as a bug since the result using just webpack is ok and using mix is not.

Please or to participate in this conversation.