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

删除回忆录丶 提交于 2019-12-03 03:03:21

问题


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"
      }
    ]
  }

回答1:


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
}



回答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.




回答3:


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';



回答4:


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.




回答5:


  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




回答6:


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.



来源:https://stackoverflow.com/questions/31197220/can-i-use-an-es6-2015-module-import-to-set-a-reference-in-global-scope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!