简体   繁体   中英

Webpack and External Libs: ProvidePlugin vs entry vs global import?

1. ProvidePlugin()

Looks like a commonly used approach. There is a gist about it, showcasing how to include whatwg-fetch polyfill into a Webpack build. Lots of answers on StackOverflow use it here and here .

new webpack.ProvidePlugin({
  '$': 'jquery',
  'jQuery': 'jquery',
  'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
})

👍 Pros

  • It works. (please update this list if I am missing something)

👎 Cons

  • Need to keep track of global libraries in the Webpack config.

2. entry: [...]

I was a little surprised by this approach when I discovered it in this gist but it works just as well.

entry: [
    'babel-polyfill',
    'whatwg-fetch',
    'jquery',
    'webpack-hot-middleware/client',
    path.join(process.cwd(), 'app/app.js')
],

👍 Pros

  • It works.
  • I can drop ProvidePlugin() entirely.

👎 Cons

  • Need to keep track of global libraries in the Webpack config.

3. Top-level import

This one is very straightforward, see this app.js example. This file is an entry-point to a React application.

/**
 * app.js
 */

import 'whatwg-fetch';
import 'babel-polyfill';
import 'jquery';

👍 Pros

  • It works just as well.
  • Easy add/remove. No need to touch the Webpack config.

👎 Cons

  • Doesn't look like this approach alone will work with jQuery plugins, eg bootstrap.js .

Observation : Between all three approaches, I haven't noticed any changes in the bundle size.

Is there one recommended way of handling global libraries with Webpack (and React)? Would any of these solutions cause a problem down the road with server-side rendering?

Thanks!

I wouldn't recommend exposing libraries as global unless you really do need it, ie the point of a module system is to explicitly declare dependencies, eg

// app.js
import $ from 'jquery';
$.ajax(...);

If you absolutely do need jQuery on the global because a third party script requires it on your page or maybe for debugging in the console then here's some information regarding the approaches you've listed:

ProvidePlugin

The ProvidePlugin won't expose jQuery on the global and is really designed to fix third-party modules which incorrectly rely on the presence of a global module so I wouldn't recommend this, eg

// app.js
$.ajax(...);

Is effectively transpiled into:

// app.js
require('jquery').ajax(...);

Entry & Top level import

These approaches won't work for a regular UMD module such as jQuery as jQuery is smart enough not to expose itself on the global when being loaded by a commonjs / amd / es6 aware loader.

These two approaches are however ideal for modules with side effects such as the babel-polyfill / whatwg-fetch because they don't export anything, they inherently mutate the global environment.


My recommendation for jQuery is therefore to use the expose-loader which is designed to expose a modules export globally, eg

// webpack.config.js
{
    module: {
        loaders: [
            test: require.resolve('jquery'),
            loader: 'expose-loader?jQuery!expose-loader?$'
        ]
    }
}

You then still need to import it in your app code:

// app.js
import $ from 'jquery';
$.ajax(...)

But it's available on the global for other scripts on the page to access if absolutely necessary:

// console
window.$
window.jQuery

NOTE: Technically you could just import 'jquery' once in your entry point when using the expose loader and then rely on the global in other modules.

As I say however, it isn't really advisable to expose a module if you don't need to, even if you happen to currently use it in every other module.

Just find out that provided lib will be overwritten, if you include several packs (entry points) in one page when you use ProvidePlugin. Examples are for RoR and Webpacker, but i assume it doesn't matter.

For example you have in your layout:

  javascript_pack_tag 'application',
                      'metronic'

And in configs you have:

  environment.plugins.append('Provide', new webpack.ProvidePlugin({
      $: 'jquery',
      jQuery: 'jquery',
      "window.jQuery": "jquery",
      "window.$": "jquery",
      _: 'underscore',
      Handlebars: 'handlebars'
  }));

If in application.js you require libraries, which mutate JQuery, you will loose all this mutation in metronic.js and in browser, even if you expose JQuery with expose-loader.

Correct me if i am wrong, probably ProvidePlugin just imports libs in each entry point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM