118

I want to expose the jQuery object to the global window object that is accessible inside the developer console in the browser. Now in my webpack config I have following lines:

plugins: [
                new webpack.ProvidePlugin({
                    $: 'jquery',
                    jQuery: 'jquery'
                })
            ]

These lines add the jQuery definitions to each file in my webpack modules. But when I build the project and try to access jQuery in the developer console like this:

window.$;
window.jQuery;

it says that these properties are undefined...

Is there a way to fix this?

Uyghur Lives Matter
  • 18,820
  • 42
  • 108
  • 144
ferbolg
  • 1,537
  • 4
  • 15
  • 19

8 Answers8

137

You need to use the expose-loader.

npm install expose-loader --save-dev

You can either do this when you require it:

require("expose?$!jquery");

or you can do this in your config:

loaders: [
    { test: require.resolve('jquery'), loader: 'expose?jQuery!expose?$' }
]

UPDATE: As of webpack 2, you need to use expose-loader instead of expose:

module: {
    rules: [{
        test: require.resolve('jquery'),
        use: [{
            loader: 'expose-loader',
            options: '$'
        }]
    }]
}
Matt Derrick
  • 5,674
  • 2
  • 36
  • 52
  • 13
    The `ProvidePlugin` should primarily used in situations where third-party libraries rely on the presence of a global variable. – Johannes Ewald Mar 17 '15 at 09:53
  • I made the incorrect assumption the question was using the provide plugin for 'lazy' purposes which I have seen a lot online but you are correct :) – Matt Derrick Mar 17 '15 at 10:18
  • 8
    This is exactly what I was looking for and just to add further, for loaders, you can do it in one line too: `{test: /jquery\.js$/, loader: 'expose?jQuery!expose?$'}` – Fernando Oct 09 '15 at 22:56
  • Just a note for others that the `require` line didn't work for me as I was getting AMD errors, but the loader-based solution did work. That said, I followed the instructions here: https://github.com/webpack/expose-loader. – icfantv Dec 22 '15 at 16:53
  • 8
    Can't you just add a first script that does `$ = require('jquery'); window.jQuery = $; window.$ = $;` ? (not needing `expose-loader`) – herman Jun 23 '16 at 08:32
  • When I put `{ test: require.resolve('jquery'), loader: 'expose?jQuery!expose?$' }` in my webpack config, then try to use "$" in my code, webpack throws and "$ is not defined" error. If I use `require("expose?$!jquery");` in my code, webpack throws an error that it can't resolve jquery. However, if I use `import $ from 'jquery', everything works. – Tyson Nero Jul 16 '16 at 21:24
  • Also, be sure you have STABLE node installed and not edge. expose no like living on the edge – JohnnyFun Sep 15 '16 at 12:10
  • I had to tweak the jquery url for this to work in my setup (TypeScript 2.1.1 with jQuery 1.9.1 and Webpack 1.3.2) `{ test: require.resolve('jquery/jquery'), loader: 'expose?jQuery!expose?$' }` – craig Dec 20 '16 at 11:58
  • 1
    According to the [expose-loader GitHub page](https://github.com/webpack-contrib/expose-loader#readme) the webpack 2 syntax is as follows: `module: { rules: [{ test: require.resolve('jquery'), use: [{ loader: 'expose-loader', options: 'jQuery' },{ loader: 'expose-loader', options: '$' }] }] }`. This is the only way I could get jQuery exposed and it's using the new [module.rules](https://webpack.js.org/guides/migrating/#module-loaders-is-now-module-rules) syntax. – Gavin Sutherland Jul 19 '17 at 12:29
  • @GavinSutherland I have updated the answer. I did not write the Webpack 2 edit but I have now corrected it. – Matt Derrick Jul 20 '17 at 12:55
93

The ProvidePlugin replaces a symbol in another source through the respective import, but does not expose the symbol on the global namespace. A classic example are jQuery plugins. Most of them just expect jQuery to be defined globally. With the ProvidePlugin you would make sure that jQuery is a dependency (e.g. loaded before) and the occurence of jQuery in their code would be replaced with the webpack raw equivalent of require('jquery').

If you have external scripts relying on the symbol to be in the global namespace (like let's say an externally hosted JS, Javascript calls in Selenium or simply accessing the symbol in the browser's console) you want to use the expose-loader instead.

In short: ProvidePlugin manages build-time dependencies to global symbols whereas the expose-loader manages runtime dependencies to global symbols.

activedecay
  • 10,129
  • 5
  • 47
  • 71
Joscha
  • 4,643
  • 1
  • 27
  • 34
40

Looks like the window object is exposed in all modules.

Why not just import/require JQuery and put:

window.$ = window.JQuery = JQuery;

You will need to ensure that this happens before requiring/importing any module that makes use of window.JQuery, either in a requiring module or in the module where it's being used.

mhess
  • 1,364
  • 14
  • 12
  • Easiest solution without adding a new dependency. Thanks! – fatihpense Nov 20 '16 at 15:52
  • That will not work wheile other nested modules using the variable,just 'not defined' – aboutqx Jan 11 '17 at 02:45
  • 4
    Well it works when using `require` while not `import` – aboutqx Jan 11 '17 at 02:58
  • @aboutqx Not sure what you mean. My answer assumed that JQuery had already been imported/required and assigned to a variable named `JQuery`. – mhess Jan 13 '17 at 17:03
  • 2
    @mhess when you use `import`,you may get error,because `import`s get sorted to the top of the file, and `require`s stay where they were put. So the run-order only changes with `import` when the window varaivble is not set. – aboutqx Jan 17 '17 at 07:00
  • for this to work, ensure thay you did not add any jquery related DefinePlugin – James Tan Sep 24 '17 at 15:32
19

This always worked for me. including for webpack 3 window.$ = window.jQuery = require("jquery");

SharpCoder
  • 18,279
  • 43
  • 153
  • 249
11

None of the above worked for me. (and I really don't like the expose-loader syntax). Instead,

I added to webpack.config.js:

var webpack = require('webpack');
module.exports = {
   plugins: [
       new webpack.ProvidePlugin({
           $: 'jquery',
       })     
   ]
}

Than all modules have access through jQuery through $.

You can expose it to the window by adding the following to any of your modules bundled by webpack:

window.$ = window.jQuery = $
Antoine Vo
  • 559
  • 4
  • 10
1

Update for Webpack v2

Install expose-loader as described by Matt Derrick:

npm install expose-loader --save-dev

Then insert the following snippet in your webpack.config.js:

module.exports = {
    entry: {
        // ...
    },
    output: {
        // ...
    },
    module: {
        loaders: [
                { test: require.resolve("jquery"), loader: "expose-loader?$!expose-loader?jQuery" }
        ]
    }
};

(from the expose-loader docs)

Cologne_Muc
  • 653
  • 6
  • 19
  • I can now no longer get this to work in any version of Webpack. Not sure what has changed but the only way I can get jQuery or $ to be recognized is to do `window.jQuery = require('jquery');` – trpt4him Jun 03 '18 at 02:10
0

In my case works

{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" } 
FeDev
  • 27
  • 3
0

Update for Webpack v2

After webpack 5 upgrade, you could face this warning.

[DEP_WEBPACK_RULE_LOADER_OPTIONS_STRING] DeprecationWarning: Using a string as loader options is deprecated (ruleSet[1].rules[7].use[0].options)

Simply change the options to

options: {
 exposes: ["$", "jQuery"],
}

will look like this:

module: {
rules: [{
    test: require.resolve('jquery'),
    use: [{
        loader: 'expose-loader',
        {
           exposes: ["$", "jQuery"],
        }
    }]
  }]
}