Predje's avatar

How to split libraries in multiple files across privates packages/components

Hello, I've been trying to split my scripts so I only load what I need for a specific page. I have private composer packages containing reusable code named Core, Back and Front. My plan was to have jquery, popper and bootstrap compiled in Core. In Back I use parsley and metismenu on every page so I wanted those to be compiled in that package as well.

Additionally I was playing with the thought of creating components, for example select, which would contain the script for chosen/select2 or something.

The problem is that for some reason I get the error that $ is undefined in the scripts that I load in after Core. So to be clear I have a Core/vendor.js which is a compiled script containing jquery, popper and bootstrap. I have a Back/vendor.js containing metismenu and parsley. I get the error $ is undefined in all the scripts I load after Core/vendor.js although it contains jquery, and additionally if I check the console jquery is loaded

My scripts look like the following

Core/vendor.js

try {
    window.$ = window.jQuery = require('jquery');
    window.Popper = require('popper.js').default;

    require('bootstrap');
} catch (e) {
    console.log(e);
}

Back/vendor.js

try {
    require('metismenu');
    require('parsleyjs');
    require('parsleyjs/dist/i18n/de');
    require('parsleyjs/dist/i18n/de.extra');
    require('parsleyjs/dist/i18n/fr');
    require('parsleyjs/dist/i18n/fr.extra');
    require('parsleyjs/dist/i18n/nl');
    require('parsleyjs/dist/i18n/nl.extra');
} catch (e) {
    console.log(e);
}

Back/app.js

$('#sidebar').metismenu();
$('form').parsley();

I changed mix to include the package name

<script src="{{ mix('/js/vendor.js', 'Core') }}"></script>
<script src="{{ mix('/js/vendor.js', 'Back) }}"></script>

This works fine as in the compiled html both are loaded as so

<script src="/core/js/vendor.js"></script>
<script src="/back/js/vendor.js"></script>

jQuery is loaded, verrified with the following

> jQuery.fn.jquery
< "3.5.1"

I got the error on both metismenu and parsley

TypeError: $(...).metisMenu is not a function
TypeError: $(...).parsley is not a function

Trying to find out what was wrong I started simple, I split up jquery and bootstrap and got the same error as well

TypeError: $(...).tooltip is not a function

I've tried wrapping the initializations in $(document).ready(function(){}); or $(function() {}); thinking it was a loading issue, but this didn't solve the problem.

Can anyone please assist me with this issue as it is doing my head in, I don't believe that I'm trying to achieve something abnormal here but I'm completely stuck on this

0 likes
1 reply
thewebartisan7's avatar

Try add in webpack.mix.js

mix.autoload({
    jquery: ['$', 'jQuery'],
});

But I don't understand why load in separated file manually, you could have one app.js and one bootstrap.js where all vendor are loaded, then in webpack.mix.js:

// Extract in vendor.js
mix.extract([
    'jquery',
    'bootstrap',
    'popper.js'
]);

This will extract all your vendor in separated file.

Please or to participate in this conversation.