tha07's avatar
Level 2

$ is not defined - Jquery not found

In my Laravel project (laravel 5.6) I installed Jquery from npm. Then I added it to webpack.mix.js.

mix.webpackConfig(webpack => {
    return { plugins: [new webpack.ProvidePlugin({
                $: "jquery",
                jQuery: ["jquery", "$"],
                "window.jQuery": "jquery",
                Popper: ["popper.js", "default"]
            })] };
});

after compiling the assets and trying to use jquery it shows

"Uncaught ReferenceError: $ is not defined"

I am using my custom JavaScript file after loading the mix file in my view.

<script src="{{ mix('/js/app.js') }}"></script>
<script type="text/javascript" src="/js/tests/tests.js"></script>

In my custom JavaScript file I added the following code to check Jquery.

$("#myCheckButton").click(function(e) {
  console.log(test);
});

I tried changing the webpack.min.js webPackconfig settings but was not able to solve it. Most questions like this recommended to put the custom js files after the mix. I think I got it right in my case

0 likes
10 replies
Tray2's avatar

I think you should remove the first /

{{ mix('js/app.js) }}
1 like
D9705996's avatar

How are you pulling in jQuery? It looks like your not from your code.

1 like
D9705996's avatar

Why not use the default laravel scaffolding as this includes jQuery out the box

1 like
hollyit's avatar

DefinePlugin just puts it in as an automatic module, exposed to other WebPack modules. Checkout the bootstrap.js file in your /resources/js and you'll see how they assign it to the window object in Laravel. You need to do that (or something similar) to make it available to non-Webpack code. The other option is using the expose-loader in Webpack.

1 like
tha07's avatar
Level 2

@hollyit

here how my bootstrap.js file looks like.

import './masonry';
import './charts';
import './popover';
import './scrollbar';
import './search';
import './sidebar';
import './skycons';
import './vectorMaps';
import './chat';
import './datatable';
import './datepicker';
import './email';
import './fullcalendar';
import './googleMaps';
import './utils';
import './sweetalert2';
import './select2';

so you're telling that i have to add jquery to this file?

Cronix's avatar

window.$ = window.jQuery = require('jquery');

1 like
D9705996's avatar

@tha07 - why have you modified webpage.mix just to pull in jQuery? As mentioned laravel includes this out the box

1 like
hollyit's avatar

@tha07 - What @Cronix suggests is how to get jQuery available in the global scope (ie: attached to the global window object). When Webpack compiles, everything is within a closure as to not pollute the global namespace.

All the ProvidePlugin does is stop you from having to do an import for that module every time you want to use it. It doesn't attach the module to the global window object.

Another thing to watch out for is that if you are using several different mix.js outputs, then each one of those will have the jQuery code loaded into it. Every time you do a mix.js(...,...) you are creating a new "chunk". That chunk is going to live within its own closure. This is how Webpack prevents different Javascript files from interfering with others, such as loading one thing that requires jQuery 1.9 and something else that requires jQuery 3+. Both can be loaded, because both are within their own enclosure within the chunks.

Having said that, the way Laravel Mix counters that problem is to use Vendor extraction. That splits the vendor files out into their own file/chunk that can be accessed from any other chunks you compile. This is basically doing the Common Chunks in Webpack.

You can see this in action yourself doing a simple mix config:

mix.browserSync({
    proxy: 'cl1.devel',
    open: false
});

mix.webpackConfig({
    plugins: [new webpack.ProvidePlugin({
        $: "jquery",
    })]
});

mix
    .js('resources/js/mix1.js', 'public/js')
    .js('resources/js/mix2.js', 'public/js')

Then make mix1.js and mix2.js just something as simple as:

console.log($);

When you build them, both files will have the jQuery code inside, as the two chunks are separate from each other and don't know what is inside the other. Basically it's like 2 different webpack builds.

Now add .extract(['jquery']) to the end of your mix and build it again. Suddenly those mix1.js and mix2.js files get very small and you have a vendor.js file with jQuery in it. Webpack makes mix1 and mix2 aware of the modules available inside vendor.js.

It does take sometime to get your head around it all, but once you do you can realize how it makes sense.

1 like
tha07's avatar
Level 2

thank you for your feedbacks. I think I should read more about mix. Actually this is a template. I go this error while compiling it. Manged to solve it by importing jquery in the app.js file like this.

import $ from 'jquery';
window.jQuery = $;
window.$ = $;

Please or to participate in this conversation.