Can I use an ES6/2015 module import to set a reference in 'global' scope?
Asked Answered
B

6

34

I have this situation where I am trying to import an existing library, which I'll call troublesome (using Webpack/Babel FWIW) and it has a global reference to jQuery in it which i am trying to resolve using module syntax.

I have successfully imported jquery into the 'local' scope of a module, via:

import jQuery from 'jquery'

so I tried:

import jQuery from 'jquery'    
import 'troublesome'

but perhaps not surprisingly, I get something like jQuery is not a function kicked back from troublesome.js

I have tried this as well:

System.import('jquery')
.then(jQuery => {
    window.jQuery = jQuery
})
import 'troublesome'

but, it turns out that System.import is part of the, so-called, 'module-loader' spec, which was pulled from the es6/2015 spec, so it isn't provided by Babel. There is a poly-fill, but Webpack wouldn't be able to manage dynamic imports accomplished via calls to System.import anyway.

but... if I call out the script files in index.html like so:

<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/troublesome/troublesome.js"></script>
<script src="the-rest-of-my-js.js"></script>

the reference to jQuery is resolved in troublesome.js and things are good, but I would prefer to avoid the script tag route as webpack doesn't manage those.

Can anyone recommend a decent strategy for dealing with scenarios like this?

update

with some guidance from @TN1ck, I was eventually able to identify one Webpack-centric solution, using the imports-loader

The configuration for this solution looks something like this:

  //...
  module: {
    loaders: [
      //...
      {
        test: require.resolve('troublesome'),
        loader: "imports?jQuery=jquery,$=jquery"
      }
    ]
  }
Bendicta answered 3/7, 2015 at 1:41 Comment(3)
Are you just trying to make jquery available in troublesome?Grantland
Did you try assigning jQuery to window object? So window.jQuery = jQuery?Plunger
jquery needs to be in the proper format in order for you to import it like that. In other words you may need to modify your local jquery and export it as a ES6 module.Ilsa
D
16

Shimming modules is the way to go: http://webpack.github.io/docs/shimming-modules.html

I quote from the page:

plugin ProvidePlugin

This plugin makes a module available as variable in every module. The module is required only if you use the variable.

Example: Make $ and jQuery available in every module without writing require("jquery").

new webpack.ProvidePlugin({
  $: "jquery",
  jQuery: "jquery",
  "window.jQuery": "jquery"
})

To use this with your webpack-config just add this object to an array called plugins in the config:

// the plugins we want to use 
var plugins = [
   new webpack.ProvidePlugin({
      $: "jquery",
      jQuery: "jquery",
      "window.jQuery": "jquery"
   })
];

// this is your webpack-config
module.exports = {
    entry: ...,
    output: ...,
    module: ...,
    plugins: plugins
}
Danieladaniele answered 6/7, 2015 at 19:1 Comment(3)
thanks @TN1ck, i was actually able to obtain the desired effect via the imports-loader, but the ProvidePlugin is in the same solution family, so you def deserve the creds for pointing me in the right direction.Bendicta
Wish you provided how to use this in Webpack? Where do I paste it?Bove
@JikkuJose At some point your webpack-config should look like this: module.exports = { entry: xxx, output: ... }. Just add plugins: [new webpack.ProvidePlugin({$: 'jquery, ...})] to the dictionary. For more information about how to use webpack, check out this guide from pete hunt.Danieladaniele
G
2

For es6/2015 I done the following.

import {jsdom} from 'jsdom';
import jQuery from 'jquery';
var window = jsdom(undefined, {}).defaultView;
var $ = jQuery(window);
//window.jQuery = $; //probably not needed but it's there if something wrong
//window.$ = $;//probably not needed but it's there if something wrong

Then you can use it as normal

var text = $('<div />').text('hello world!!!').text();
console.log(text);

Hope this helps.

Goingson answered 10/11, 2015 at 11:54 Comment(0)
B
0

Importing jQuery into your module does not make it available for 'troublesome'. Instead, you could create a thin wrapper module for 'troublesome' that provides jQuery and any other required "globals".

troublesome-module.js:

// Bring jQuery into scope for troublesome.
import jQuery from 'jquery';
// Import any other 'troublesome'-assumed globals.

// Paste or have build tool interpolate existing troublesome.js code here.

Then in your code you should be able to

import 'troublesome-module';
Birth answered 5/7, 2015 at 20:5 Comment(0)
V
0

I've had a similar issue using jspm and dygraphs. The way i solved it was to use dynamic loading like you attempted using System.import but the important part was to chain-load each consecutive "part" using System.import again inside the promise onfulfillment handler (then) after setting the global namespace variable. In my scenario I actually had to have several import steps separated between then handlers.

The reason it didn't work with jspm, and probably why it didn't work for you as well is that the import ... from ... syntax is evaluated before any code, and definitely before System.import which of async.

In your case it could be as simple as:

import jQuery from 'jquery';

window.jQuery = jQuery;
System.import('troublesome').then(troublesome => {
 // Do something with it...
});

Also note that the System module loader recommendation has been left out of the final ES6 specification, and a new loader spec is being drafted.

Ventricle answered 5/7, 2015 at 21:11 Comment(0)
D
0
  1. run npm install import-loader.
  2. replace import 'troublesome' with import 'imports?jQuery=jquery,$=jquery!troublesome.

In my opinion, this is the simplest solution to your question. It is similar to the answer you wrote in your question @TN1ck, but without altering your webpack config. For more reading, see: https://github.com/webpack/imports-loader

Dissepiment answered 23/11, 2016 at 1:6 Comment(0)
M
0

Shimming is fine and there are various ways of resolving this, but as per my answer here, the simplest is actually just to revert to using require for the loading of the library that requires the global dependency - then just make sure your window. assignment is before that require statement, and they are both after your other imports, and your ordering should remain as intended. The issue is caused by Babel hoisting imports such that they all get executed before any other code.

Miscue answered 28/11, 2016 at 14:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.