'jQuery is not defined' when use ES6 import

12,353

Solution 1

According to this comment and apply it to your case, when you're doing:

import $ from 'jquery'
import jQuery from 'jquery'

you aren't actually using a named export.

The problem is that when you do import $ ..., import jQuery ... and then import 'owlCarousel' (which depends on jQuery), these are evaluated before, even if you declare window.jQuery = jquery right after importing jquery. That's one of the ways ES6 module semantics differs from CommonJS' require.

One way to get around this is to instead do this:

Create file jquery-global.js

// jquery-global.js
import jquery from 'jquery';
window.jQuery = jquery;
window.$ = jquery;

then import it in you main file:

// main.js
import './jquery-global.js';
import 'owlCarousel' from '../../node_modules/owlcarousel/owl-carousel/owl.carousel'

class App {
  ...
  _initSlider() {
    $("#partners-carousel").owlCarousel();
  }
}

That way you make sure that the jQuery global is defined before owlCarousel is loaded.

Solution 2

@Serge You should have mentioned in your question that you are using browserify & babelify to bundle/transpile your code (I knew it from comments), this will help people find the correct answer to your question.

As of 2021, ECMA2015+/ES6+ don't allow the use of import-maps/bare-module-path natively in the browser. So basically you can't do the following directly in the browser, because the browser doesn't behave like nodejs, it doesn't understand how/where to fetch for the source of your scripts, you can't just say:

import $ from 'jquery'  
import jQuery from 'jquery'

However, you can do this by the help of bundlers like WebPack which opens that door for import-maps/bare-module-path to be used in the browser. Besides, huge work is currently being done to support the implementation of import-maps directly in the browser without the need of bundlers, but it's not implemented yet. I know that this question is old enough for the OP to follow, but in general, you can use WebPack to bundle your code and import your dependencies the way you mentioned.

P.S. Regarding the answer proposed by @egel in Oct 2016 (which is an old answer with limited solutions at that time) some people asked for more clarifications. Please note the following statement by Nicolás Bevacqua regarding the scope of ES6+ modules:

Declarations in ES6 modules are scoped to that module. That means that any variables declared inside a module aren’t available to other modules unless they’re explicitly exported as part of the module’s API (and then imported in the module that wants to access them).

ES6+ module system is awesome and makes things much more organized, but can we fully implement ES6+ modules in the browser without the need of bundlers/transpilers? This is a tough question. Things may get harder when some of your JavaScript dependencies are just old/classic scripts that do not support the ES6+ modules system, and do not use the export keyword to export functions/values for you. Here, developers tend to do some workarounds to solve the problem in hand. The window object is used to attach functions/variables in order to use them across all modules. Here the window object is used as a carrier to transfer functions/data across different modules within your code base, and this is not a recommended approach though.

Below is quoted from javascript.info:

If we really need to make a window-level global variable, we can explicitly assign it to window and access as window.user. But that’s an exception requiring a good reason.

Share:
12,353
Serge
Author by

Serge

Updated on June 05, 2022

Comments

  • Serge
    Serge about 2 years

    My code:

    import $ from 'jquery'
    import jQuery from 'jquery'
    import owlCarousel from '../../node_modules/owlcarousel/owl-carousel/owl.carousel'
    
    class App {
        …
        _initSlider() {
            $("#partners-carousel").owlCarousel();
        }
    }
    

    I have 'jQuery is not defined' in browser console. What's wrong? I can use jQuery as $ in methods of this class, but not with name 'jQuery'.

    • Joe Clay
      Joe Clay over 8 years
      What are you using to load/transpile your code?
    • Serge
      Serge over 8 years
      browserify & babelify. Here is gulp task: gulp.task('compile', () => { return browserify( { entries: files.source.script, debug: !production, transform: [babelify.configure({ 'presets': ['es2015'] })] } ) .bundle() .pipe(source('script.js')) .pipe(buffer()) .pipe(production ? uglify() : gutil.noop()) .pipe(gulp.dest(files.dest.scripts)) .pipe(production ? gutil.noop() : livereload()); });
    • Daniel Cheung
      Daniel Cheung over 8 years
    • deleteddeleted
      deleteddeleted over 8 years
      @Serge did you find a solution for this?
  • Aurelien
    Aurelien almost 6 years
    Indeed this works, but can you please tell us more? Why is the ordering only guaranteed with your method? Is it documented somewhere? Thanks!
  • Shemang David
    Shemang David about 5 years
    This seems to be the solution that worked for me. Can you please explain a little more why it happens this way? thanks so much for this solution by the way.