Confusion over various webpack shimming approaches
Asked Answered
B

2

7

I'm a little confused on the various ways webpack allows to expose a variable that isn't available on npm or to be put in the bundle. I was able to expose the google visualizations chart script's global google var by using

resolve: {
    extensions: ['.js', '.json'],
    alias: {
      'google': path.resolve(__dirname, 'vendor', 'google.js')
    }
  }

combined with

  plugins: [
    new webpack.ProvidePlugin({
      'google': 'google'
    })
  ]

however looking at the webpack docs there a couple other ways to shim, which look like they might do something similar. There is imports-loader and exports-loader, and script-loader. I know that I've linked to the docs, but I still find their descriptions of when these four should be used a bit unclear.

Also looking at this example, is this require not assigned to a variable? Where is it meant to go? And where is the documentation on what is going on with this syntax?

require("imports?$=jquery!./file.js")

Can someone provide me some examples of when each of these should be used?

Baum answered 8/6, 2017 at 15:30 Comment(0)
C
4

scripts-loader

I never used this myself, but the idea is simple I guess. I think it can be used if for some reason you want to inject a script or a function or something in one of the modules/files you have no control over them.

imports-loader & exports-loader

In one of the apps I worked on we had to use tinymce which in its older versions was dependent on this being always window because it was built to work as a global script. Not as a CommonJS or ES module.

So in order to fix that, we had to use the import-loader so it can inject window to the script. Here how it looked like in webpack.config.js

{ test: require.resolve('tinymce/tinymce'), use: ['imports?this=>window', 'exports?tinymce'] }

Which says inject window in place of this & also we are using exports-loader here so we can export the global tinymce as a default export named tinymce so we can use it as a normal module in our app.

Thankfully all of this is already fixed in the latest releases.

ProvidePlugin

In my experience, this is useful when a library is depending on another library being in a global scope or something. Like jQuery plugins for example, they do use one of these $, window.$, jQuery & window.jQuery

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

So what this plugin will do is to make sure when webpack sees one of these variations it will provide the jQuery object to it instead.

The difference between this & imports-loader for example that you might not know which variation is used by which script. So you let webpack handle this while the imports-loader is kind of more specific.

I hope this helped you a bit to understand the differences between all of them, also this is the new documentation page which I think better than the one you were checking https://webpack.js.org/guides/shimming/

Cloudless answered 14/6, 2017 at 19:33 Comment(5)
What's the ! syntax?Baum
Webpack adds the option to overload the require() function with it's own syntax to allow for using loaders inline. That's why the weird syntax here require("imports?$=jquery!./file.js") this is just saying import $ as jQuery for file.jsCloudless
oh, is that why in the docs it's just require(....) not like const module = require('module')? can you show an example of this using inline with this syntax please?Baum
Storing it in a variable or not has nothing to do with the loader, it depends on what you want to do with the require()ed or imported script. This is a very simple one already require("imports?$=jquery!./file.js") lets say file.js is a jQuery plugin & depends on jQuery as $ then you are making sure that it gets it gets jQuery as $Cloudless
You can also check @arturkin example below.Cloudless
S
4

imports and exports loaders are very simple to understand. If you use one of them, or both, your module is wrapped into another function with exports and imports.

For example, I'm using paho-mqtt module meant to be used like global <script src=""> on the page:

import Paho from 'imports-loader?this=>window!exports-loader?Paho!paho-mqtt';

//and this is transformed by webpack to something like:
(function(window){

    //wow you can use `window here`, `this` in the global context === window.


   // original module code here
   // that exposes global var `Paho`


   module.exports = Paho;

})(this);
Sublimation answered 15/6, 2017 at 13:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.