expose-loader
expose-loader copied to clipboard
jQuery is not being exposed
Bug report
Exposing jQuery doesn't work. A global $, jQuery, a window.$, window.jQuery, or even globalThis.$ or globalThis.jQuery all do not exist in the resulting bundle, and therefor in the browser, and therefor in the browser console. They all return undefined.
Actual Behavior
> window.jQuery
undefined
Expected Behavior
> window.jQuery
function() // and more jQuery-related stringness
How Do We Reproduce?
Add this rule:
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
exposes: [
"jQuery",
"$",
],
}
},
Build whatever project (doesn't seem to matter) and trying resolving window.jQuery in the browser console.
Please paste the results of npx webpack-cli info here, and mention other relevant information
System:
OS: Windows 10 10.0.19044
CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
Memory: 14.43 GB / 31.76 GB
Binaries:
Node: 16.15.1 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.18 - ~\AppData\Roaming\npm\yarn.CMD
npm: 8.13.2 - C:\Program Files\nodejs\npm.CMD
Browsers:
Chrome: 103.0.5060.114
Edge: Spartan (44.19041.1266.0), Chromium (103.0.1264.49)
Internet Explorer: 11.0.19041.1566
And as always, scripts like these are missing the one browser I'm actually using. Firefox. Also probably pretty important: Webpack 5.73.0, expose-loader 4.0.0, jQuery 1.11.2.
Here's my full webpack.config.js:
const webpack = require('webpack');
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const opts = {
rootDir: process.cwd(),
devBuild: process.env.NODE_ENV !== 'production',
};
module.exports = {
entry: {
app: './src/js/bootstrap'
},
mode: opts.devBuild ? 'development' : 'production',
devtool: opts.devBuild ? 'inline-source-map' : 'source-map',
output: {
path: path.join(opts.rootDir, 'dist'),
pathinfo: opts.devBuild,
filename: 'js/[name].js'
},
optimization: {
minimizer: [
new TerserPlugin(),
new CssMinimizerPlugin(),
]
},
plugins: [
// Extract css files to seperate bundle
new MiniCssExtractPlugin({
filename: 'css/[name].css',
chunkFilename: 'css/[id].css'
}),
// Copy fonts and images to dist
new CopyWebpackPlugin({
patterns: [
{ from: 'src/fonts', to: 'fonts' },
{ from: 'src/img', to: 'img' }
]
}),
new CleanWebpackPlugin(),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.$': 'jquery',
'velocity': 'velocity-animate',
'ScrollMagic': 'scrollmagic'
}),
],
module: {
rules: [
// Babel-loader
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
}
},
// Css-loader & sass-loader
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
},
// Embed or emit fonts & images
{
test: /\.(png|jpg|jpeg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/,
type: 'asset', // Inline data-URI when under the maxSize, otherwise a file is emitted.
parser: {
dataUrlCondition: {
maxSize: 100000
}
}
},
// Expose jQuery globally
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
exposes: [
"jQuery",
"$",
],
}
},
]
},
resolve: {
extensions: ['.js', '.scss'],
modules: [path.resolve(__dirname, '..\\node_modules'), path.resolve(__dirname, 'node_modules')],
alias: {
request$: 'xhr'
}
},
stats: {
warnings: false
}
};
Even if I change it to exposes: [ "jQueryFOOBAR", "$" ], that identifier jQueryFOOBAR is nowhere to be found in the entire bundle that is being produced. It's as if it just nothing at all happens.
Also good to know, require.resolve('jquery') resolves to the jquery package, and the file really does exist.
I've also tried moving the expose-loader to the top of the rules. No effect.
Also whether or not import "jquery"; is at the very top of my bootstrap, makes no difference.
Also good to know is that jQuery is being provided correctly by the ProvidePlugin. That part works. But ProvidePlugin doesn't provide globals - it only provides automatic imports, as we know. No good for modules that aren't modules and really do need a global variable.
Please provide example of a usage
What kind of usage do you mean? Just webpack --config webpack.config.js --progress and watch an app.js being built.
Turns out if i change
test: require.resolve('jquery'),
To:
test: /jquery\.js/,
It works. But why?
Again, require.resolve('jquery') absolutely does return a valid&existing path to jQuery. And I have another project that is identical to this one, when it comes to exposing jQuery, where it does work as documented. Only difference is the jQuery version, which I cannot change atm.
Further digging:
When I place a simple top-level console.log("here!") in node_modules\expose-loader\dist\index.js, it is NOT being called. It's as if the whole module is completely being ignored. That's why I started looking at the test whether that might be wrong.
So it now correctly generates all those EXPOSE_LOADER things (and, to be expected, it now also places here! in the terminal). Fluff knows why all of that is neccesary just to get window.jQuery, but whatever.
The question is still: why must I use a different test? What is wrong with using require.resolve even though it generates the correct filename??
You can load jquery from node_modules (i.e. require.resolve('jquery') will work for your), but also you can loader jquery not from node_modules, so your test will not work, thati is why I asked about example, also I want to look how you loader jQuery in your app to undestand potential problems
Closing due to inactivity. Please test with latest version and feel free to reopen if still regressions. Thanks!