Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

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, e.g. 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!

like image 949
Sahat Yalkabov Avatar asked Oct 06 '16 05:10

Sahat Yalkabov


People also ask

What is externals in webpack?

Webpack externals tell Webpack to exclude a certain import from the bundle. Often externals are used to exclude imports that will be loaded via CDN. For example, suppose you are implementing server-side rendering with Vue and Express, but your client-side code imports Vue via a CDN.

What is shimming webpack?

The webpack compiler can understand modules written as ES2015 modules, CommonJS or AMD. However, some third party libraries may expect global dependencies (e.g. $ for jQuery ). The libraries might also create globals which need to be exported.

Does webpack use CommonJS?

Webpack supports the following module types natively: ECMAScript modules. CommonJS modules.


1 Answers

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

// 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, e.g.

// 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, e.g.

// 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.

like image 57
riscarrott Avatar answered Sep 18 '22 05:09

riscarrott