Repository navigation
“TypeError: jquery__WEBPACK_IMPORTED_MODULE_0__ is not a function” with jQuery 4 (ESM) #256
Description
Activity
I also encountered that issue when migrating the project I am working on to jQuery 4 as I also exposed
$andjQueryglobally usingexpose-loader.I managed to workaround it by using modify-source-webpack-plugin to rewrite the ESM import statements on the fly so that jQuery can be imported the correct way.
Below is the modified
webpack.config.mjsfrom the gist linked above.import {ModifySourcePlugin, ReplaceOperation} from "modify-source-webpack-plugin"; import HtmlWebpackPlugin from "html-webpack-plugin"; import resolve from "enhanced-resolve"; const myResolve = resolve.create.sync({ conditionNames: ["import", "module"] }); export default { entry: ["./cjs.cjs", "./esm.mjs"], module: { rules: [ { test: myResolve(import.meta.dirname, "jquery"), loader: "expose-loader", type: "javascript/auto", options: { exposes: [ { globalName: "$", moduleLocalName: "$", override: true }, { globalName: "jQuery", moduleLocalName: "jQuery", override: true }] }, }, ], }, plugins: [ new HtmlWebpackPlugin(), // ensure jQuery 4.0 can be imported from a js module when exposed globally by webpack expose-loader new ModifySourcePlugin({ rules: [ { test: /\.mjs$/, operations: [ new ReplaceOperation('all', "import jQuery from 'jquery'", "import {jQuery} from 'jquery'"), new ReplaceOperation('all', 'import jQuery from "jquery"', 'import {jQuery} from "jquery"'), new ReplaceOperation('all', "import \\$ from 'jquery'", "import {$$} from 'jquery'"), new ReplaceOperation('all', 'import \\$ from "jquery"', 'import {$$} from "jquery"') ] } ] }) ], };
Just interesting why do you still use this loader (it was created for really old code), why do not use directly at the top of your entrypoint:
import { jQuery as $ } from 'jquery'; globalThis.$ = $;
There are three solution:
- globalThis supported and you polyfill it
import jQuery from 'jquery'; globalThis.$ = jQuery; globalThis.jQuery = jQuery; // ... more code or in other module $(document).ready(function(){ $("button").click(function(){ $("p").hide(); // Selects all <p> elements and hides them }); });
- globalThis is not supported or you don't polyfill globalThis
import jQuery from 'jquery'; var getGlobal = function () { if (typeof globalThis !== 'undefined') { return globalThis; } if (typeof window !== 'undefined') { return window; } if (typeof self !== 'undefined') { return self; } if (typeof global !== 'undefined') { return global; } return (function () { return this; })() || Function('return this')() }; const pseudoGlobalThis = getGlobal(); pseudoGlobalThis.$ = jQuery; pseudoGlobalThis.jQuery = jQuery; $(document).ready(function(){ $("button").click(function(){ $("p").hide(); // Selects all <p> elements and hides them }); });
- Using such configuration (RECOMMENDED for jQuery):
webpack.config.js
{ plugins: [ new webpack.ProvidePlugin({ "$": ["jquery", "default"], "jQuery": ["jquery", "default"], }) ], }
$(document).ready(function(){ $("button").click(function(){ $("p").hide(); // Selects all <p> elements and hides them }); });
Feel free to feedback, soon this loader will be deprecated, I will provide link in webpack examples with jQuery example for other developers
Just interesting why do you still use this loader (it was created for really old code),
The project I am working on uses some legacy dependencies that expect
$orjQueryto be in the global scope so the use of that loader.why do not use directly at the top of your entrypoint:
import { jQuery as $ } from 'jquery';
globalThis.$ = $;
Oh I did not know about this, thanks !
I confirm that it works great and it simplifies my webpack config a lot.
For those interested, see this commit migrating my webpack project to jQuery 4.0.
I also polyfilled
globalThisusingbabel-plugin-transform-globalthisfor older browsers.Reacted by Alexander Akait
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Bug Description
jQuery 4.0.0 was released this weekend, now using ES modules, and it no longer works with expose-loader from ESM consumers.
Here’s the closest I got to making it work:
This lets
window.$andconst $ = require("jquery")work as expected. However, if I doimport $ from "jquery"from an ES module, I get a module object$ === { $: [function], default: [function], jQuery: [function] }rather than the expected$ === [function].Link to Minimal Reproduction and step to reproduce
https://gist.github.com/andersk/b64e2d2c49f2db4bf294a04c27989e5f
Run
npm install; npx webpack --mode=developmentand opendist/index.htmlin a browser.Expected Behavior
Should see four paragraphs:
Actual Behavior
and in the browser console:
Environment
Is this a regression?
None
Last Working Version
No response
Additional Context
Probably related: