How to call imported jquery functions in dev tools console? [duplicate] - javascript

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?

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: '$'
}]
}]
}

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.

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.

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

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 = $

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)

In my case works
{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" }

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"],
}
}]
}]
}

Related

Webpack script-loader vs. imports-loader?module=>false

I'm trying include jquery (and other legacy libs) into a webpack project.
I need the jquery to be available globally, also in HTML.
There are so many options to achieve this, but here are 2 I came up with:
Option 1.
// webpack.config.js
module: {
noParse: /jquery/,
rules: [
{
test: /jquery/,
use: ['imports-loader?module=>false']
}
]
},
// entrypoint.js
import 'jquery';
Option 2.
// webpack.config.js
module: {
rules: [
{
test: /jquery/,
use: ['script-loader']
}
]
},
// entrypoint.js
import 'jquery';
Which of these would be better (Or some other method?)
Both of these seem to work identically, however I think option 1 would be better since script-loader (option 2) uses eval.

Named functions in a javascript file using Webpack 4

I just started using Webpack 4 in a project and am new to Webpack. Once Webpack 4 was implemented, I noticed that named functions kept erroring saying [functionName] is not defined.
I have looked quite extensively over the last few days and have tried multiple options with no success. I am hoping for someone to help me work through this in a more direct fashion way.
function openNav(obj) {
...do something
}
#foreach (object in list)
{
...create some HTML
}
const bundleFileName = 'bundle';
const dirName = 'wwwroot/dist';
module.exports = (env, argv) => {
return {
mode: argv.mode === "production" ? "production" : "development",
entry: [
'./src/Index.js',
'./src/css/site.css',
'./src/js/app.js'
],
output: {
filename: bundleFileName + '.js',
path: path.resolve(__dirname, dirName)
},
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: 'style-loader' }, { loader: 'css-loader' }]
}
]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: bundleFileName + '.css'
})
]
};
};
I expected the button in the razor file to send the object over to the named function so something can happen like it did previously before webpack
You've said you're trying to use openNav from an onclick attribute. The problem there is that openNav has to be a global to be used that way, but Webpack is a module bundler. Functions at the top level of modules aren't globals. (Which is a good thing.)
The solution is to not use onxyz-attribute-style event handlers. Instead, use modern event handling (addEventListener, probably with at least some event delegation).
To ease your transition from the old way to the modern way, you can expose a function globally from within a module like this (on browsers):
window.openNav = openNav;
I strongly recommend only doing that temporarily to make it easier to transition to modern event handling.
thats because your webpack config isnt set to understand how to handle javascript files, add this to your rules key:
{
test: /\.jsx?/,
loader: 'babel-loader'
}
you will also need to install babel loader that is in a version compatible with your babel core, for v7^ you need to install #babel/core #babel/loader etc, otherwise, babel-loader etc

Using expose-loader with webpack 2 to load a module

I have jwplayer in my lib/ folder because no node_module exists. I tried to use expose-loader in order to be able to import it. In my webpack, I have the following basic setup in order to get this to work:
const path = require('path');
module.exports = {
// ...
module: {
rules: [{
test: /\.jwplayer\.js$/,
use: {
loader: 'expose-loader',
options: 'jwplayer', // have also tried `options: { name: 'jwplayer' }`
},
}]
},
resolve: {
alias: {
jwplayer: path.join(__dirname, './lib/jwplayer-7.7.4/jwplayer.js'),
}
},
externals: {
window: 'Window',
}
};
The strange thing is, jwplayer is exposed on the window object, but it is not available as a module.
import jwplayer from 'jwplayer';
console.log(jwplayer); // Object {} (not jwplayer)
console.log(window.jwplayer); // function jwplayer() {}
Am I loading it incorrectly? How should I load in jwplayer with webpack 2?
That's not how you use the expose loader. The expose loader tells to webpack to expose something to the global context when the bundle is loaded. My understanding is that you want to use jwplayer inside the bundle itself.
You can use the script-loader, that's how I usually import scripts (analytics, for instance)
Actually you can use
externals: ['jwplayer'],
Because externals is for passing global variables inside the bundle to be able to use them as a dependency and then you can import your library as any other
import jwplayer from 'jwplayer';
webpack documentation

How To Use ScrollMagic with GSAP and Webpack

In order to use ScrollMagic with GSAP, you need to load the animation.gsap.js plugin. With Webpack you would do something like this to accomplish that (assuming you use the CommonJS syntax and installed everything with npm):
var TweenMax = require('gsap');
var ScrollMagic = require('scrollmagic');
require('ScrollMagicGSAP');
To make sure that this actually works, you have to add an alias to your Webpack configuration, so that Webpack knows where the plugin lives.
resolve: {
alias: {
'ScrollMagicGSAP': 'scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap'
}
}
Unfortunately, ScrollMagic keeps throwing an error, when you are using this configuration and the CommonJS syntax like above.
(ScrollMagic.Scene) -> ERROR calling setTween() due to missing Plugin 'animation.gsap'. Please make sure to include plugins/animation.gsap.js
The Solution
You have to tell Webpack to stop using the AMD syntax by adding the following loader that deactivates the define() method.
// Webpack 4+
module: {
rules: [
{ parser: { amd: false }}
]
}
// Webpack <= 3
// Don’t forget to install the loader with `npm install imports-loader --save-dev`
module: {
loaders: [
{ test: /\.js$/, loader: 'imports-loader?define=>false'}
// Use this instead, if you’re running Webpack v1
// { test: /\.js$/, loader: 'imports?define=>false'}
]
}
Why?
The problem lies in the fact that Webpack supports the AMD (define) and CommonJS (require) syntax. That is why the following factory script within plugins/animation.gsap.js jumps into the first if statement and fails silently. That is why setTween() etc. are never added to the ScrollMagic Constructor.
By telling Webpack not to support the AMD syntax (using the loader mentioned above), the plugin jumps into the second if statement correctly, embracing the CommonJS syntax.
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['ScrollMagic', 'TweenMax', 'TimelineMax'], factory);
} else if (typeof exports === 'object') {
// CommonJS
// Loads whole gsap package onto global scope.
require('gsap');
factory(require('scrollmagic'), TweenMax, TimelineMax);
} else {
// Browser globals
factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.TweenMax || root.TweenLite, root.TimelineMax || root.TimelineLite);
}
I hope this prevents other people from spending a whole evening trying to figure out what is going on.
The solution I came across that doesn't require you to alter your webpack.config.js file and actually works for me can be found here: https://github.com/janpaepke/ScrollMagic/issues/665
The gist of it is to make sure you have ScrollMagic and GSAP added via npm (hopefully that's obvious) as well as imports-loader:
npm install --save scrollmagic gsap
npm install --save-dev imports-loader
Then in the file you want to use ScrollMagic with GSAP do the following imports:
import { TimelineMax, TweenMax, Linear } from 'gsap';
import ScrollMagic from 'scrollmagic';
import 'imports-loader?define=>false!scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap';
Using Webpack 4.x and imports-loader 0.8.0
medoingthings solution has since changed syntax to include "-loader" suffix.
module: {
loaders: [
{ test: /\.js$/, loader: 'imports-loader?define=>false'}
]
}
https://webpack.js.org/guides/migrating/#automatic-loader-module-name-extension-removed
In imports-loader 1.1.0, the syntax of the configuration has changed a bit, so now you have to use the following to get the ScrollMagic plugins to work:
{
test: [
path.join(config.root, '/node_modules/scrollmagic/scrollmagic/uncompressed/plugins/jquery.ScrollMagic.js'),
path.join(config.root, '/node_modules/scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators.js')
],
use: [
{
loader: 'imports-loader',
options: {
additionalCode: 'var define = false;'
}
}
]
}
Hopefully this helps others.
I was having the same issue and found this question.
For those using Webpack 5 I believe imports-loader is out of date so according to the webpack docs add this code to your js rule to disable AMD:
{
test: /\.js$/,
include: /node_modules/,
parser: {
amd: false
}
}
documentation: https://webpack.js.org/configuration/module/#ruleparser

Initializing third-part plugin in webpack bundle.js

One of my module is external plugin (WOW effect), which needs to be initialize in index.html to works properly by using:
<script>
new WOW().init();
</script>
If I use the plugin as a completely external file - it works. But when I compile it with webpack it gives me an error:
Uncaught ReferenceError: wow is not defined.
My config file looks like this:
module.exports = {
entry: './modules/_entry.js',
output: {
filename: 'bundle.js'
}
};
and _entry.js contains:
require("./wow.js");
What I am doing wrong?
There are two possibilities:
Externals The benefit of this one is that you can easly exchange your local script file for example for a CDN one. In this method, the source of the script is an external vendor file.
Have a folder with you vendor scripts, like WOW.
Link to it in your HTML file using <script src="vendors/WOW.js">.
You are free to make the initialization like you indicated above, inside another <script> tag.
Add externals configuration to your webpack config:
var config = {
entry: [...],
output: {...},
externals: {
Wow: 'WOW'
},
module: {...},
plugins: [...]
};
From now on, you have access to an artificial module Wow in all your application modules and you can import or require them (although in case of WOW, I don't think you would need it).
Expose-loader This way lets you move to the global scope modules that you would normally use as... well, modules :) In this method, the source of the script is a module (either yours own, or installed with npm).
Install the plugin: npm install expose-loader --save-dev
Add the expose loader configuration to your webpack config file:
var config = {
entry: [...],
output: {...},
module: {
loaders: [{
...
}, {
test: 'path/to/your/module/wow.min.js',
loader: "expose?WOW"
}]
},
plugins: [...]
};
This should make the WOW a global variable, usable inside <script> tags.

Categories

Resources