2

I'm using Webpack and Babel to build an Angular1.4 project, written in ECMA6 syntax. I'd like to use ECMAScript 6 import/export default module syntax, but sometimes I have to use Webpack loaders, such as expose to globally expose modules (e.g. jquery, required to be a global object by angular): require("expose?jquery!jquery").

Is there a way to write ECMAScript6 imports with Webpack loaders? Something like:

import "expose?jquery!jquery"

I can't mix require() calls with import calls, because imports hoist to the top of the module and break the order of dependency loading. E.g.

require("expose?jquery!jquery);
import angular from "angular";

transpiles to:

var angular = require("angular");
require("expose?jquery!jquery);

which breaks the build, because window.jquery is required by my Angular directives that expect angular.element to be full jquery, not angular's jqLite.

And require breaks with modules, exported with exports default.

Boris Burkov
  • 13,420
  • 17
  • 74
  • 109
  • You do not need to make any object global. Including angular and jquery. Include them using import. (Having no idea what is expose. We have angular 1.5 + webpack + bower and no expose is used.) – Petr Averyanov Mar 22 '16 at 09:55
  • @PetrAveryanov how do you make `angular.element` refer to real `jquery`, not `jqLite` then? Probably, you don't? Unfortunately, some of my directives assume that `angular.element` is the real `jQuery` with extended set of methods, so I have to make angular detect global `jQuery` upon bootload and for that purpose I need `window.jquery` set. Also, take note that even angular1.5 assigns `window.angular` to itself globally upon bootload. – Boris Burkov Mar 22 '16 at 10:02
  • 3
    Angular, lodash and jquery creates global objects, however you are not forced to treat them in this way. To have angular.element to be jquery, you just need to include jquery before angular as usual. So just import jquery from 'jquery' followed by import angular from 'angular' is enough. – Petr Averyanov Mar 22 '16 at 10:15
  • @PetrAveryanov Damn, you're right! Interestingly, when you say require("jquery"), it understands that it's CommonJS and calls its factory with `noGlobal` argument set to `true`: `factory( global, true )`. But, if I `import` it, it runs just `factory(global)`! I wonder, how it works. Спасибо, Петр. Пожалуйста, оформите Ваш комментарий как ответ и я его плюсану. Строго говоря, это не ответ на вопрос в общем случае, но мою проблему он решил. – Boris Burkov Mar 22 '16 at 10:26

1 Answers1

0

Why don't you give Webpack's Provide plugin a shot?

In your webpack.config.js:

var webpack = require('webpack'); 
// Remember to install webpack locally with `npm install webpack`

module.exports = {
    ...
    plugins: [
        new webpack.ProvidePlugin({
            jQuery: 'jquery'
        })
    ],
    ...
}

This way you'll have jQuery as a global throughout your project without having to manually require it!

Edit: I use jQuery with the uppercase Q, you are of course free to use it all lowercase. You should also be able to use both!

Edit 2: Another thing worth noting is that it's not that Webpack breaks with require and export default, it's that Babel has actually fixed a misconception in version 6: if you want to use require with an ES6/7 module you have to require the default export, so require('myModule').default. In general, you should only use require with CommonJS modules, while you can use import with (almost) everything.

Gian Marco Toso
  • 11,676
  • 5
  • 29
  • 38
  • I tried and failed. You can't use ProvidePlugin, because it will introduce jquery as a dependency in Angular IF Angular refers to `jquery` variable as a global somewhere, implying that it's globally available. But in fact Angular doesn't. It specifically refers to `window.jquery`, when looking for a global instance of jquery. So, ProvidePlugin doesn't do the trick in this case. Thanks for suggestion, though. – Boris Burkov Mar 22 '16 at 09:58
  • Have you tried, then, to set `jquery` as a global? `global.jquery = require('jquery')`. Or maybe use provide with both Angular AND jQuery. – Gian Marco Toso Mar 22 '16 at 10:01
  • I can't. :) If I write `import jquery from "jquery"; window.jquery = jquery; import angular from "angular"`, it is transpiled into `var jquery = require("jquery); var angular = require("angular"); window.jquery = jquery`, which breaks the order - by the time angular is loaded, `window.jquery` is not set yet. – Boris Burkov Mar 22 '16 at 10:05
  • Have you tried using `global.jquery = require('jquery')` instead of `window.jquery`? – Gian Marco Toso Mar 22 '16 at 10:21
  • It's not about `jquery`, it's about `import angular`. No matter, what I do with jquery, `import angular` will be hoisted before it. – Boris Burkov Mar 22 '16 at 10:33