24

so i have a few vendor files that i need to run from window scoped (it's a bunch of window scoped functions) plus i have some polyfills that i would like to bundle into the vendor bundle as well.

So i tried something like this:

new webpack.optimize.CommonsChunkPlugin({
    name: 'vendor',
    filename: 'js/vendor.min.js',
    minChunks: Infinity,
})

entry: {
    'vendor' : ['./vendor.js', './vendor2.js', './polyfills.js']
}

Now when i run my webpack build it does generate my vendor bundle but it's all wrapped in a webpackJsonP wrapper so the functions are not accessible on the window scope.

I've also looked at using something like the ProvidePlugin but i couldn't make that work at all since i don't have a defined name like jQuery where everything is mapped under.

Is this even possible in webpack?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Mick Feller
  • 882
  • 1
  • 8
  • 16
  • Can you name one vendor for example? – Legends Feb 28 '18 at 23:18
  • We for example use IBM Coremetrics for analytics purposes – Mick Feller Feb 28 '18 at 23:34
  • Is this library/file public, do you have a link? How do you mean it doesn't have a name like jQuery? If you load one of your vendor scripts, the regular way, in a browser, how does it register itself globally on windows? – Legends Mar 01 '18 at 11:11
  • ... on `window` – Legends Mar 01 '18 at 11:25
  • Here is a link: https://libs.coremetrics.com/eluminate.js this is one example i have a few more of these libraries. What I mean with it's not like jquery is that it's not namespaced or wrapped in one function like $. All functions are on a global scope exposed to the window scope. Hope that make sense, oh and you might have to run that file through a beautifier. And it doesn't expose itself like: window.funcionName unfortunately otherwise it would be easy. – Mick Feller Mar 01 '18 at 11:29
  • Your best choice I guess, would be to use a `script-loader` which registers everything in the global namsespace. take a look [here](https://github.com/webpack/docs/wiki/shimming-modules#script-loader). You can use a config for `script-loader` or use it inline with `import exec from 'script-loader!./eluminate.js';` – Legends Mar 01 '18 at 11:47

3 Answers3

20

Use the script-loader plugin:

If you want the whole script to register in the global namespace you have to use script-loader. This is not recommend, as it breaks the sense of modules ;-) But if there is no other way:

npm install --save-dev script-loader

Webpack docs

This loader evaluates code in the global context, just like you would add the code into a script tag. In this mode every normal library should work. require, module, etc. are undefined.

Note: The file is added as string to the bundle. It is not minimized by webpack, so use a minimized version. There is also no dev tool support for libraries added by this loader.

Then in your entry.js file you could import it inline:

import  "script-loader!./eluminate.js"

or via config:

module.exports = {
  module: {
    rules: [
      {
        test: /eluminate\.js$/,
        use: [ 'script-loader' ]
      }
    ]
  }
}

and in your entry.js

import './eluminate.js';

As I said, it pollutes the global namespace:

enter image description here

Legends
  • 21,202
  • 16
  • 97
  • 123
  • 1
    Cool thanks for the answer I'm going to try this and report back soon! – Mick Feller Mar 01 '18 at 12:26
  • I don't know how you got this to work, but i keep getting: [Script Loader] ReferenceError: CM_DDX is not defined. i see most properties in the window scope now so that's a step but it keeps falling on that error. And i see in your screenshot it is there. I added this in my entry file: import "script-loader!./coremetrics/eluminate"; and i had to exclude that specific bundle from my babel task otherwise it was completely failing. – Mick Feller Mar 01 '18 at 15:34
  • Sorry, but i don't use `babel` for transpiling, but `TypeScript`. I just installed the `script-loader` package and did it the inline way: `import "script-loader!./eluminate.js"`. That's all. – Legends Mar 01 '18 at 16:45
  • Cool, thabks anyways! I'll go setup a minimal setup and give that some test runs I am at least on the right track. I appreciate it! – Mick Feller Mar 01 '18 at 17:40
  • Put it on github, perhaps we can take a look at your minimal setup together then... – Legends Mar 01 '18 at 18:02
  • 2
    I used this approach but unfortunately script-loader uses eval, and we've got CSP configured to block eval, which makes this a very difficult thing to achieve. – Antony O'Neill Dec 18 '18 at 12:32
  • 2
    @AntonyO'Neill Fell free to create a CSP compliant `script-loader` plugin ;.-) – Legends Dec 18 '18 at 23:03
  • 1
    Haha! I'm not sure if that's possible... I'm trying a different approach now, using a query parameter on the import to load the JS as a file and load it in a script tag in HTML. – Antony O'Neill Dec 19 '18 at 11:27
7

script-loader should-not be used anymore. You can use raw-loader instead:

npm install --save-dev raw-loader

And:

import('!!raw-loader!./nonModuleScript.js').then(rawModule => eval.call(null, rawModule.default));

I'm using !! before raw-loader because I'm in the case described in the documentation:

Adding !! to a request will disable all loaders specified in the configuration

AymKdn
  • 3,327
  • 23
  • 27
2

Both above solutions will have issues when the site is enforcing some content-security-policy(CSP) rules due to use of unsafe eval expressions, which is absolutely a good thing. (always treat security as first-class citizen in web ;))

Alternative solutions i have found so far are, assuming you are also working on a legacy codebase and having this kind of need

For UMD modules, consider import-loader, an example

 test: require.resolve('jquery'),
 use: {
      loader: 'imports-loader',
      options: {
        wrapper: {
          thisArg: 'window',
          args: {
            module: false,
            exports: false,
            define: false,
          },
        },
      },
    },
  },

For CJS modules export to global namespace, consider expose-loader.

Also if you have time, give webpack shimming a read.

Allen
  • 4,431
  • 2
  • 27
  • 39