I'm using Webpack to build an Angular 1.4 project. The project makes use of several jQuery plugins, which are wrapped into angular directives. Those directives internally use angular.element, probably implying that angular.element is the real jQuery, not jqLite.
I want angular to auto-detect jQuery and use it instead of jqLite. I tried to require jquery locally in my entry point module app.js: require('jquery') and to expose jQuery globally with require(expose?$!expose?jQuery!jquery).
Still, whatever I do, angular.element refers to jqLite.
My research resulted in several findings:
- Even when imported as a CommonJS module, Angular assigns itself to a global variable window.angular, so I don't need toexposeit with Webpack: Does Angular assign itself to `window.angular` globally, when loaded as CommonJS module?.
- ProviderPlugin doesn't seem to do the trick: it doesn't expose jQuery to global namespace; instead, for every module that depends on global name jQuery, it inserts require('jquery')in it. I'm not 100% sure, but looks like Angular doesn't accessjQueryfrom global namespace directly, instead, it tries to accesswindow.jQueryinbindJQueryfunction, so this approach doesn't help: Expose jQuery to real Window object with Webpack.
- For the same reason as ProviderPlugin, imports-loaderseems unfit: Angular wantswindow.jQuery, not justjQuery.
- With expose-loader, jquery makes it to the window object. My problem was that Babel hoists all of its imports to the top of module in the resulting code. Hence, althoughrequire(expose?jquery!jquery)was beforeimport angular from "angular"in source files, in bundlerequire("angular")is at the top of the file, before jquery, so by the time Angular is imported, jquery is not yet available. I wonder, how to use Webpack loaders with ECMA6 import syntax.
- There was a suggestion to use importsyntax instead ofrequiresyntax with jquery:import "jquery"orimport $ from "jquery", notrequire(jquery): (Petr Averyanov: How to use Webpack loaders syntax ( imports/exports/expose) with ECMAScript 6 imports?). jquery source code is wrapped with a special wrapper, which idenitifies how jquery is required (with AMD/require, CommonJS or globally with<script>statement). Based on that it sets a special argumentnoGlobalfor jquery fabric and either createswindow.jQueryor not, based on the value ofnoGlobal. As of jquery 2.2.4, uponimport "jquery"noGlobal === trueandwindow.jQueryis not created. IIRC, some older versions of jquery didn't recognizeimportas CommonJS import and addedimported jquery to global namespace, which allowed angular to use it.
Details: here's my app.js:
'use strict';
require("expose?$!expose?jQuery!jquery");
require("metisMenu/dist/metisMenu");
require("expose?_!lodash");
require("expose?angular!angular");
import angular from "angular";
import "angular-animate";
import "angular-messages";
import "angular-resource";
import "angular-sanitize";
import "angular-ui-router";
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";
import "angular-bootstrap";
require("../assets/styles/style.scss");
require("../assets/fonts/pe-icon-7-stroke/css/pe-icon-7-stroke.css");
// Import all html files to put them in $templateCache
// If you need to use lazy loading, you will probably need
// to remove these two lines and explicitly require htmls
const templates = require.context(__dirname, true, /\.html$/);
templates.keys().forEach(templates);
import HomeModule from "home/home.module";
import UniverseDirectives from "../components/directives";
angular.module("Universe", [
    "ngAnimate",
    "ngMessages",
    "ngResource",
    "ngSanitize",
    "ui.router",
    "ui.bootstrap",
    HomeModule.name,
    UniverseDirectives.name,
])
.config(function($urlRouterProvider, $locationProvider, $stateProvider){
    // $urlRouterProvider.otherwise('/');
    // $locationProvider.html5Mode(true);
    $stateProvider
      .state('test', {
        url: "/test",
        template: "This is a test"
      });
});




