]> source.dussan.org Git - jquery.git/commitdiff
Core: Fix the exports setup to make bundlers work with ESM & CommonJS
authorMichał Gołębiowski-Owczarek <m.goleb@gmail.com>
Mon, 11 Mar 2024 23:39:34 +0000 (00:39 +0100)
committerGitHub <noreply@github.com>
Mon, 11 Mar 2024 23:39:34 +0000 (00:39 +0100)
We cannot pass a single file via the `module` condition as then
`require( "jquery" )` will not return jQuery but instead the module object
with `default`, `$` & `jQuery` as keys. Instead:

1. For Node.js, detected via the `node` condition:
    1. Expose a regular CommonJS version to `require`
    2. Expose a tiny wrapper over CommonJS to `import`
2. For bundlers, detected via the `module` condition:
    1. Expose a regular ESM version to `import`
    2. Expose a tiny wrapper over ESM to `require`
3. If neither Node.js nor bundlers are detected (no `node` or `module`
   conditions`):
    1. Expose a regular CommonJS version to `require`
    2. Expose a regular ESM version to `import`

The reasons for such definitions are as follows:
1. In Node.js, one can synchronously import from a CommonJS file inside of
   an ESM one but not vice-versa. To use an ESM file in a CommonJS one,
   a dynamic import is required and that forces asynchronicity.
2. In some bundlers CommonJS is not necessarily enabled - e.g. in Rollup without
   the CommonJS plugin. Therefore, the ESM version needs to be pure ESM.
   However, bundlers allow synchronously calling `require` on an ESM file. This
   is possible since bundlers merge the files before they are passed to
   the browser to execute and the final bundles no longer contain async import
   code.
3. Bare ESM & CommonJS versions are provided to non-Node non-bundler
   environments where we cannot assume interoperability between ESM & CommonJS
   is supported.
4. Bare versions cannot be supplied to Node or bundlers as projects using both
   ESM & CommonJS to fetch jQuery would result in duplicate jQuery instances,
   leading to increased JS size and disjoint data storage.

In addition to the above changes, the `script` condition has been dropped. Only
Webpack documents this condition and it's not clear when exactly it's triggered.
Adding support for a new condition can be added later without a breaking change;
removing is not so easy.

The `production` & `development` conditions have been removed as well. They were
not really applied correctly; we'd need to provide both of them to each current
leaf which would double the size of the definition for the `.` & `./slim` entry
points. In jQuery, the only difference between development & production builds
is minification; there are no logic changes so we can pass unminified versions
to all the tooling, expecting minification down the line.

As for the factory entry points:
1. Node.js always gets the CommonJS version
2. Bundlers always get the ESM version
3. Other tools take the ESM version when using `import` and the CommonJS when
   using `require`.

The complexity is lower than for the `.` & `./slim` entry points because there's
no default export to handle so Node/bundler wrapper files are not necessary.

Other changes:
* Tests: Change "node:assert" to "node:assert/strict"; the former is deprecated
* Docs: Mention that the CommonJS module doesn't expose named exports
* Tests: Run Node & bundler tests for all the above cases

Fixes gh-5416
Closes gh-5429

35 files changed:
.gitignore
build/fixtures/README.md
build/release/dist.js
build/tasks/node_smoke_tests.js
dist-module/jquery.node-module-wrapper.js
dist-module/jquery.node-module-wrapper.slim.js
dist/jquery.bundler-require-wrapper.js [new file with mode: 0644]
dist/jquery.bundler-require-wrapper.slim.js [new file with mode: 0644]
eslint.config.js
package-lock.json
package.json
test/bundler_smoke_tests/lib/run-rollup.js [new file with mode: 0644]
test/bundler_smoke_tests/lib/run-webpack.js [new file with mode: 0644]
test/bundler_smoke_tests/lib/utils.js [new file with mode: 0644]
test/bundler_smoke_tests/rollup-commonjs.config.js [new file with mode: 0644]
test/bundler_smoke_tests/rollup-pure-esm.config.js [new file with mode: 0644]
test/bundler_smoke_tests/run-jsdom-tests.js [new file with mode: 0644]
test/bundler_smoke_tests/src-esm-commonjs/jquery-require.cjs [new file with mode: 0644]
test/bundler_smoke_tests/src-esm-commonjs/main.js [new file with mode: 0644]
test/bundler_smoke_tests/src-pure-esm/main.js [new file with mode: 0644]
test/bundler_smoke_tests/test.html [new file with mode: 0644]
test/bundler_smoke_tests/webpack.config.cjs [new file with mode: 0644]
test/node_smoke_tests/commonjs/factory/document_missing.cjs
test/node_smoke_tests/commonjs/lib/ensure_global_not_created.cjs
test/node_smoke_tests/commonjs/lib/ensure_iterability_es6.cjs
test/node_smoke_tests/commonjs/lib/ensure_jquery.cjs
test/node_smoke_tests/dual/factory/import-and-require-factory.js [new file with mode: 0644]
test/node_smoke_tests/dual/lib/jquery-require-factory.cjs [new file with mode: 0644]
test/node_smoke_tests/dual/lib/jquery-require.cjs [new file with mode: 0644]
test/node_smoke_tests/dual/regular/import-and-require.js [new file with mode: 0644]
test/node_smoke_tests/module/factory/document_missing.js
test/node_smoke_tests/module/lib/ensure_global_not_created.js
test/node_smoke_tests/module/lib/ensure_iterability_es6.js
test/node_smoke_tests/module/lib/ensure_jquery.js
test/node_smoke_tests/module/regular/window_present_originally.js

index 7f58545fd332f3e0659adbd36d0850e4cee67588..ff0a4190060d3f77a653239fe7fc98157c5cb51a 100644 (file)
@@ -9,6 +9,7 @@
 .sizecache.json
 yarn.lock
 .eslintcache
+tmp
 
 npm-debug.log*
 
@@ -16,6 +17,8 @@ npm-debug.log*
 # the ESLint config & package.json files
 /dist/*
 !/dist/package.json
+!/dist/jquery.bundler-require-wrapper.js
+!/dist/jquery.bundler-require-wrapper.slim.js
 
 # Ignore everything in the `dist-module` folder except for the ESLint config,
 # package.json & Node module wrapper files
index 9e9bf7169702cdc7904196edd8850efe4b24d258..2511a51c3189ef180092d61a8a6ff7de269a6cbe 100644 (file)
@@ -120,6 +120,8 @@ If you need to use jQuery in a file that's not an ECMAScript module, you can use
 const $ = require( "jquery" );
 ```
 
+The CommonJS module _does not_ expose named `$` & `jQuery` exports.
+
 #### Individual modules
 
 jQuery is authored in ECMAScript modules; it's also possible to use them directly. They are contained in the `src/` folder; inspect the package contents to see what's there. Full file names are required, including the `.js` extension.
index e71dd3b4dbb9bf6688dea443f6cf94617b469095..78dc5064f2d85d0a926b7ebee045252a888f744d 100644 (file)
@@ -17,6 +17,8 @@ module.exports = function( Release, files, complete ) {
                "LICENSE.txt",
                "AUTHORS.txt",
                "dist/package.json",
+               "dist/jquery.bundler-require-wrapper.js",
+               "dist/jquery.bundler-require-wrapper.slim.js",
                "dist-module/package.json",
                "dist-module/jquery.node-module-wrapper.js",
                "dist-module/jquery.node-module-wrapper.slim.js"
index 6f99b9981df7808b22806740230df73b85cbf84c..7d6588648cdd79e0abb7c768bb7aceb3e4da59fe 100644 (file)
@@ -5,8 +5,8 @@ const util = require( "node:util" );
 const exec = util.promisify( require( "node:child_process" ).exec );
 const verifyNodeVersion = require( "./lib/verifyNodeVersion" );
 
-const allowedLibraryTypes = [ "regular", "factory" ];
-const allowedSourceTypes = [ "commonjs", "module" ];
+const allowedLibraryTypes = new Set( [ "regular", "factory" ] );
+const allowedSourceTypes = new Set( [ "commonjs", "module", "dual" ] );
 
 if ( !verifyNodeVersion() ) {
        return;
@@ -19,8 +19,8 @@ if ( !verifyNodeVersion() ) {
 // each other, e.g. so that they don't share the `require` cache.
 
 async function runTests( { libraryType, sourceType, module } ) {
-       if ( !allowedLibraryTypes.includes( libraryType ) ||
-                       !allowedSourceTypes.includes( sourceType ) ) {
+       if ( !allowedLibraryTypes.has( libraryType ) ||
+                       !allowedSourceTypes.has( sourceType ) ) {
                throw new Error( `Incorrect libraryType or sourceType value; passed: ${
                        libraryType
                } ${ sourceType } "${ module }"` );
@@ -127,6 +127,28 @@ async function runDefaultTests() {
                        libraryType: "factory",
                        sourceType: "module",
                        module: "./dist-module/jquery.factory.slim.module.js"
+               } ),
+
+               runTests( {
+                       libraryType: "regular",
+                       sourceType: "dual",
+                       module: "jquery"
+               } ),
+               runTests( {
+                       libraryType: "regular",
+                       sourceType: "dual",
+                       module: "jquery/slim"
+               } ),
+
+               runTests( {
+                       libraryType: "factory",
+                       sourceType: "dual",
+                       module: "jquery/factory"
+               } ),
+               runTests( {
+                       libraryType: "factory",
+                       sourceType: "dual",
+                       module: "jquery/factory-slim"
                } )
        ] );
 }
index bda9eb3d7effc9fa77d0037cad14c5f4f06cd77c..cafadcd1990b6435ab3119a219e150f8e3bb6561 100644 (file)
@@ -1,4 +1,5 @@
+// Node.js is able to import from a CommonJS module in an ESM one.
 import jQuery from "../dist/jquery.js";
-const $ = jQuery;
-export { jQuery, $ };
+
+export { jQuery, jQuery as $ };
 export default jQuery;
index 900f32fc29de9ba231a61c7d1bf33938e1ebcc36..2508b6a4703e545b7b40b7141d18d01bccb88f85 100644 (file)
@@ -1,4 +1,5 @@
+// Node.js is able to import from a CommonJS module in an ESM one.
 import jQuery from "../dist/jquery.slim.js";
-const $ = jQuery;
-export { jQuery, $ };
+
+export { jQuery, jQuery as $ };
 export default jQuery;
diff --git a/dist/jquery.bundler-require-wrapper.js b/dist/jquery.bundler-require-wrapper.js
new file mode 100644 (file)
index 0000000..e6ac3af
--- /dev/null
@@ -0,0 +1,5 @@
+"use strict";
+
+// Bundlers are able to synchronously require an ESM module from a CommonJS one.
+const { jQuery } = require( "../dist-module/jquery.module.js" );
+module.exports = jQuery;
diff --git a/dist/jquery.bundler-require-wrapper.slim.js b/dist/jquery.bundler-require-wrapper.slim.js
new file mode 100644 (file)
index 0000000..c34b6d0
--- /dev/null
@@ -0,0 +1,5 @@
+"use strict";
+
+// Bundlers are able to synchronously require an ESM module from a CommonJS one.
+const { jQuery } = require( "../dist-module/jquery.slim.module.js" );
+module.exports = jQuery;
index 952d39c71cf4c57f8cab28c3f58cb11983ab21f7..fb70e1a885ded66d465ecad942b4887136d2b04c 100644 (file)
@@ -10,6 +10,7 @@ export default [
                // See https://github.com/eslint/eslint/discussions/17412
                ignores: [
                        "external",
+                       "**/tmp",
                        "test/data/json_obj.js"
                ]
        },
@@ -18,8 +19,8 @@ export default [
                files: [
                        "eslint.config.js",
                        "Gruntfile.cjs",
-                       "test/node_smoke_tests/commonjs/**",
-                       "test/node_smoke_tests/module/**",
+                       "test/bundler_smoke_tests/**/*",
+                       "test/node_smoke_tests/**",
                        "test/promises_aplus_adapters/**",
                        "test/middleware-mockserver.cjs"
                ],
@@ -260,8 +261,8 @@ export default [
 
        {
                files: [
-                       "test/node_smoke_tests/commonjs/**",
-                       "test/node_smoke_tests/module/**",
+                       "test/bundler_smoke_tests/**",
+                       "test/node_smoke_tests/**",
                        "test/promises_aplus_adapters/**",
                        "test/middleware-mockserver.cjs"
                ],
@@ -317,7 +318,25 @@ export default [
 
                languageOptions: {
                        globals: {
-                               ...globals.browser,
+                               ...globals.es2021,
+                               define: false,
+                               module: false,
+                               Symbol: false
+                       }
+               }
+       },
+
+       {
+               files: [
+                       "dist/jquery.bundler-require-wrapper.js",
+                       "dist/jquery.bundler-require-wrapper.slim.js",
+                       "dist-module/jquery.node-module-wrapper.js",
+                       "dist-module/jquery.node-module-wrapper.slim.js"
+               ],
+
+               languageOptions: {
+                       globals: {
+                               ...globals.node,
                                ...globals.es2021,
                                define: false,
                                module: false,
index 23a384f6d83196f55e02f0d4d05740f96d6e8d1a..cf6f3043960a44d5ec59adc3880503fbad7ed16f 100644 (file)
@@ -13,6 +13,8 @@
         "@babel/core": "7.24.0",
         "@babel/plugin-transform-for-of": "7.23.6",
         "@prantlf/jsonlint": "14.0.3",
+        "@rollup/plugin-commonjs": "25.0.7",
+        "@rollup/plugin-node-resolve": "15.2.3",
         "@swc/core": "1.4.6",
         "@types/selenium-webdriver": "4.1.22",
         "body-parser": "1.20.2",
@@ -42,6 +44,7 @@
         "rollup": "4.12.1",
         "selenium-webdriver": "4.18.1",
         "sinon": "9.2.4",
+        "webpack": "5.90.3",
         "yargs": "17.7.2"
       }
     },
         "node": ">=6.0.0"
       }
     },
+    "node_modules/@jridgewell/source-map": {
+      "version": "0.3.5",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
+      "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
     "node_modules/@jridgewell/sourcemap-codec": {
       "version": "1.4.15",
       "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
         "node": ">= 14"
       }
     },
+    "node_modules/@rollup/plugin-commonjs": {
+      "version": "25.0.7",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-25.0.7.tgz",
+      "integrity": "sha512-nEvcR+LRjEjsaSsc4x3XZfCCvZIaSMenZu/OiwOKGN2UhQpAYI7ru7czFvyWbErlpoGjnSX3D5Ch5FcMA3kRWQ==",
+      "dev": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "commondir": "^1.0.1",
+        "estree-walker": "^2.0.2",
+        "glob": "^8.0.3",
+        "is-reference": "1.2.1",
+        "magic-string": "^0.30.3"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^2.68.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@rollup/plugin-commonjs/node_modules/glob": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@rollup/plugin-commonjs/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@rollup/plugin-node-resolve": {
+      "version": "15.2.3",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz",
+      "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==",
+      "dev": true,
+      "dependencies": {
+        "@rollup/pluginutils": "^5.0.1",
+        "@types/resolve": "1.20.2",
+        "deepmerge": "^4.2.2",
+        "is-builtin-module": "^3.2.1",
+        "is-module": "^1.0.0",
+        "resolve": "^1.22.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^2.78.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@rollup/pluginutils": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz",
+      "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "^1.0.0",
+        "estree-walker": "^2.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      },
+      "peerDependencies": {
+        "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+      },
+      "peerDependenciesMeta": {
+        "rollup": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@rollup/rollup-android-arm-eabi": {
       "version": "4.12.1",
       "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.1.tgz",
         "@types/node": "*"
       }
     },
+    "node_modules/@types/eslint": {
+      "version": "8.56.5",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.5.tgz",
+      "integrity": "sha512-u5/YPJHo1tvkSF2CE0USEkxon82Z5DBy2xR+qfyYNszpX9qcs4sT6uq2kBbj4BXY1+DBGDPnrhMZV3pKWGNukw==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "node_modules/@types/eslint-scope": {
+      "version": "3.7.7",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+      "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+      "dev": true,
+      "dependencies": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
     "node_modules/@types/estree": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
       "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
       "dev": true
     },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.15",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+      "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+      "dev": true
+    },
     "node_modules/@types/json5": {
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
       "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
       "dev": true
     },
+    "node_modules/@types/resolve": {
+      "version": "1.20.2",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+      "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+      "dev": true
+    },
     "node_modules/@types/selenium-webdriver": {
       "version": "4.1.22",
       "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.1.22.tgz",
       "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
       "dev": true
     },
+    "node_modules/@webassemblyjs/ast": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz",
+      "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/helper-numbers": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/floating-point-hex-parser": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz",
+      "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-api-error": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz",
+      "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-buffer": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz",
+      "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-numbers": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz",
+      "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/floating-point-hex-parser": "1.11.6",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz",
+      "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-wasm-section": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz",
+      "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@webassemblyjs/helper-buffer": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/ieee754": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz",
+      "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==",
+      "dev": true,
+      "dependencies": {
+        "@xtuc/ieee754": "^1.2.0"
+      }
+    },
+    "node_modules/@webassemblyjs/leb128": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz",
+      "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==",
+      "dev": true,
+      "dependencies": {
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/utf8": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz",
+      "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/wasm-edit": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz",
+      "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@webassemblyjs/helper-buffer": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/helper-wasm-section": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.11.6",
+        "@webassemblyjs/wasm-opt": "1.11.6",
+        "@webassemblyjs/wasm-parser": "1.11.6",
+        "@webassemblyjs/wast-printer": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-gen": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz",
+      "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-opt": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz",
+      "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@webassemblyjs/helper-buffer": "1.11.6",
+        "@webassemblyjs/wasm-gen": "1.11.6",
+        "@webassemblyjs/wasm-parser": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-parser": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz",
+      "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@webassemblyjs/helper-api-error": "1.11.6",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.6",
+        "@webassemblyjs/ieee754": "1.11.6",
+        "@webassemblyjs/leb128": "1.11.6",
+        "@webassemblyjs/utf8": "1.11.6"
+      }
+    },
+    "node_modules/@webassemblyjs/wast-printer": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz",
+      "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.6",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@xtuc/ieee754": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+      "dev": true
+    },
+    "node_modules/@xtuc/long": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+      "dev": true
+    },
     "node_modules/accepts": {
       "version": "1.3.8",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
         "node": ">=0.4.0"
       }
     },
+    "node_modules/acorn-import-assertions": {
+      "version": "1.9.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz",
+      "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^8"
+      }
+    },
     "node_modules/acorn-jsx": {
       "version": "5.3.2",
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
         "temp-fs": "^0.9.9"
       }
     },
+    "node_modules/buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "node_modules/builtin-modules": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz",
+      "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/bytes": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
         "fsevents": "~2.3.2"
       }
     },
+    "node_modules/chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
     "node_modules/cliui": {
       "version": "8.0.1",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
         "node": ">=0.8.0"
       }
     },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "dev": true
+    },
     "node_modules/concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
       "dev": true
     },
+    "node_modules/deepmerge": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+      "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/define-data-property": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
         "node": ">= 0.8"
       }
     },
+    "node_modules/enhanced-resolve": {
+      "version": "5.15.1",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.1.tgz",
+      "integrity": "sha512-3d3JRbwsCLJsYgvb6NuWEG44jjPSOMuS73L/6+7BZuoKm3W+qXnSoIYVHi8dG7Qcg4inAY4jbzkZ7MnskePeDg==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/entities": {
       "version": "4.5.0",
       "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
         "node": ">= 0.4"
       }
     },
+    "node_modules/es-module-lexer": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.4.1.tgz",
+      "integrity": "sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==",
+      "dev": true
+    },
     "node_modules/es-set-tostringtag": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
         "node": ">=4.0"
       }
     },
+    "node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "dev": true
+    },
     "node_modules/esutils": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
         "through": "~2.3.1"
       }
     },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
     "node_modules/exit-hook": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-4.0.0.tgz",
         "node": ">= 6"
       }
     },
+    "node_modules/glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true
+    },
     "node_modules/globals": {
       "version": "14.0.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+      "dev": true
+    },
     "node_modules/graphemer": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/is-builtin-module": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz",
+      "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==",
+      "dev": true,
+      "dependencies": {
+        "builtin-modules": "^3.3.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/is-callable": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
         "node": ">=0.10.0"
       }
     },
+    "node_modules/is-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+      "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+      "dev": true
+    },
     "node_modules/is-negative-zero": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
       "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==",
       "dev": true
     },
+    "node_modules/is-reference": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+      "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "*"
+      }
+    },
     "node_modules/is-regex": {
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
         "node": "*"
       }
     },
+    "node_modules/jest-worker": {
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
     "node_modules/js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
       "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
       "dev": true
     },
+    "node_modules/loader-runner": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+      "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.11.5"
+      }
+    },
     "node_modules/locate-path": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
         "yallist": "^3.0.2"
       }
     },
+    "node_modules/magic-string": {
+      "version": "0.30.8",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz",
+      "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.4.15"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/make-dir": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
       "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
       "dev": true
     },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
     "node_modules/merge2": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
         "node": ">= 0.6"
       }
     },
+    "node_modules/neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true
+    },
     "node_modules/nise": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz",
         "node": ">= 0.8"
       }
     },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
     "node_modules/range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
       }
     },
     "node_modules/safe-array-concat": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz",
-      "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
+      "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
       "dev": true,
       "dependencies": {
-        "call-bind": "^1.0.5",
-        "get-intrinsic": "^1.2.2",
+        "call-bind": "^1.0.7",
+        "get-intrinsic": "^1.2.4",
         "has-symbols": "^1.0.3",
         "isarray": "^2.0.5"
       },
         "node": ">=v12.22.7"
       }
     },
+    "node_modules/schema-utils": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+      "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv-keywords": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+      "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+      "dev": true,
+      "peerDependencies": {
+        "ajv": "^6.9.1"
+      }
+    },
+    "node_modules/schema-utils/node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
     "node_modules/selenium-webdriver": {
       "version": "4.18.1",
       "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.18.1.tgz",
       "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
       "dev": true
     },
+    "node_modules/serialize-javascript": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+      "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+      "dev": true,
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
     "node_modules/serve-static": {
       "version": "1.15.0",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
       }
     },
     "node_modules/set-function-length": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz",
-      "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==",
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+      "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
       "dev": true,
       "dependencies": {
-        "define-data-property": "^1.1.2",
+        "define-data-property": "^1.1.4",
         "es-errors": "^1.3.0",
         "function-bind": "^1.1.2",
-        "get-intrinsic": "^1.2.3",
+        "get-intrinsic": "^1.2.4",
         "gopd": "^1.0.1",
-        "has-property-descriptors": "^1.0.1"
+        "has-property-descriptors": "^1.0.2"
       },
       "engines": {
         "node": ">= 0.4"
         "node": ">=6"
       }
     },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
     "node_modules/spawn-command": {
       "version": "0.0.2",
       "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz",
       "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==",
       "dev": true
     },
+    "node_modules/tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/temp-fs": {
       "version": "0.9.9",
       "resolved": "https://registry.npmjs.org/temp-fs/-/temp-fs-0.9.9.tgz",
         "rimraf": "bin.js"
       }
     },
+    "node_modules/terser": {
+      "version": "5.29.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz",
+      "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/source-map": "^0.3.3",
+        "acorn": "^8.8.2",
+        "commander": "^2.20.0",
+        "source-map-support": "~0.5.20"
+      },
+      "bin": {
+        "terser": "bin/terser"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser-webpack-plugin": {
+      "version": "5.3.10",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz",
+      "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.20",
+        "jest-worker": "^27.4.5",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.1",
+        "terser": "^5.26.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.1.0"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "uglify-js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/terser/node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
     "node_modules/text-table": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
         "node": ">=18"
       }
     },
+    "node_modules/watchpack": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+      "dev": true,
+      "dependencies": {
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/webidl-conversions": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
         "node": ">=12"
       }
     },
+    "node_modules/webpack": {
+      "version": "5.90.3",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz",
+      "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==",
+      "dev": true,
+      "dependencies": {
+        "@types/eslint-scope": "^3.7.3",
+        "@types/estree": "^1.0.5",
+        "@webassemblyjs/ast": "^1.11.5",
+        "@webassemblyjs/wasm-edit": "^1.11.5",
+        "@webassemblyjs/wasm-parser": "^1.11.5",
+        "acorn": "^8.7.1",
+        "acorn-import-assertions": "^1.9.0",
+        "browserslist": "^4.21.10",
+        "chrome-trace-event": "^1.0.2",
+        "enhanced-resolve": "^5.15.0",
+        "es-module-lexer": "^1.2.1",
+        "eslint-scope": "5.1.1",
+        "events": "^3.2.0",
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.2.9",
+        "json-parse-even-better-errors": "^2.3.1",
+        "loader-runner": "^4.2.0",
+        "mime-types": "^2.1.27",
+        "neo-async": "^2.6.2",
+        "schema-utils": "^3.2.0",
+        "tapable": "^2.1.1",
+        "terser-webpack-plugin": "^5.3.10",
+        "watchpack": "^2.4.0",
+        "webpack-sources": "^3.2.3"
+      },
+      "bin": {
+        "webpack": "bin/webpack.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependenciesMeta": {
+        "webpack-cli": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-sources": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/webpack/node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/webpack/node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
     "node_modules/whatwg-encoding": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
index 1322abdf22143e964ea26b74216f2927be0313c2..c4aed69ec0d875cfd7b98b1a881180de46930a64 100644 (file)
@@ -7,33 +7,39 @@
   "exports": {
     ".": {
       "node": {
-        "module": "./dist-module/jquery.module.js",
         "import": "./dist-module/jquery.node-module-wrapper.js",
-        "require": "./dist/jquery.js"
+        "default": "./dist/jquery.js"
       },
-      "production": "./dist-module/jquery.module.min.js",
-      "development": "./dist-module/jquery.module.js",
-      "script": "./dist/jquery.min.js",
-      "default": "./dist-module/jquery.module.min.js"
+      "module": {
+        "import": "./dist-module/jquery.module.js",
+        "default": "./dist/jquery.bundler-require-wrapper.js"
+      },
+      "import": "./dist-module/jquery.module.js",
+      "default": "./dist/jquery.js"
     },
     "./slim": {
       "node": {
-        "module": "./dist-module/jquery.slim.module.js",
         "import": "./dist-module/jquery.node-module-wrapper.slim.js",
-        "require": "./dist/jquery.slim.js"
+        "default": "./dist/jquery.slim.js"
+      },
+      "module": {
+        "import": "./dist-module/jquery.slim.module.js",
+        "default": "./dist/jquery.bundler-require-wrapper.slim.js"
       },
-      "production": "./dist-module/jquery.slim.module.min.js",
-      "development": "./dist-module/jquery.slim.module.js",
-      "script": "./dist/jquery.slim.min.js",
-      "default": "./dist-module/jquery.slim.module.min.js"
+      "import": "./dist-module/jquery.slim.module.js",
+      "default": "./dist/jquery.slim.js"
     },
     "./factory": {
       "node": "./dist/jquery.factory.js",
-      "default": "./dist-module/jquery.factory.module.js"
+      "module": "./dist-module/jquery.factory.module.js",
+      "import": "./dist-module/jquery.factory.module.js",
+      "default": "./dist/jquery.factory.js"
     },
     "./factory-slim": {
       "node": "./dist/jquery.factory.slim.js",
-      "default": "./dist-module/jquery.factory.slim.module.js"
+      "module": "./dist-module/jquery.factory.slim.module.js",
+      "import": "./dist-module/jquery.factory.slim.module.js",
+      "default": "./dist/jquery.factory.slim.js"
     },
     "./src/*.js": "./src/*.js"
   },
@@ -53,8 +59,9 @@
     "pretest": "npm run qunit-fixture && npm run babel:tests && npm run npmcopy",
     "qunit-fixture": "node build/tasks/qunit-fixture.js",
     "start": "node -e \"require('./build/tasks/build.js').buildDefaultFiles({ watch: true })\"",
+    "test:bundlers": "npm run pretest && npm run build:all && node test/bundler_smoke_tests/run-jsdom-tests.js",
     "test:browser": "npm run pretest && npm run build:main && npm run test:unit -- -b chrome -b firefox -h",
-    "test:browserless": "npm run pretest && npm run build:all && node build/tasks/node_smoke_tests.js && node build/tasks/promises_aplus_tests.js && npm run test:unit -- -b jsdom -m basic",
+    "test:browserless": "npm run pretest && npm run build:all && node test/bundler_smoke_tests/run-jsdom-tests.js && node build/tasks/node_smoke_tests.js && node build/tasks/promises_aplus_tests.js && npm run test:unit -- -b jsdom -m basic",
     "test:jsdom": "npm run pretest && npm run build:main && npm run test:unit -- -b jsdom -m basic",
     "test:node_smoke_tests": "npm run pretest && npm run build:all && node build/tasks/node_smoke_tests.js",
     "test:promises_aplus": "npm run build:main && node build/tasks/promises_aplus_tests.js",
@@ -92,6 +99,8 @@
     "@babel/core": "7.24.0",
     "@babel/plugin-transform-for-of": "7.23.6",
     "@prantlf/jsonlint": "14.0.3",
+    "@rollup/plugin-commonjs": "25.0.7",
+    "@rollup/plugin-node-resolve": "15.2.3",
     "@swc/core": "1.4.6",
     "@types/selenium-webdriver": "4.1.22",
     "body-parser": "1.20.2",
     "rollup": "4.12.1",
     "selenium-webdriver": "4.18.1",
     "sinon": "9.2.4",
+    "webpack": "5.90.3",
     "yargs": "17.7.2"
   },
   "commitplease": {
diff --git a/test/bundler_smoke_tests/lib/run-rollup.js b/test/bundler_smoke_tests/lib/run-rollup.js
new file mode 100644 (file)
index 0000000..d18c450
--- /dev/null
@@ -0,0 +1,42 @@
+import { rollup } from "rollup";
+
+import { loadConfigFile } from "rollup/loadConfigFile";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+const pureEsmConfigPath = path.resolve(
+       dirname, "..", "rollup-pure-esm.config.js" );
+const commonJSConfigPath = path.resolve(
+       dirname, "..", "rollup-commonjs.config.js" );
+
+// See https://rollupjs.org/javascript-api/#programmatically-loading-a-config-file
+async function runRollup( name, configPath ) {
+
+       console.log( `Running Rollup, version: ${ name }` );
+
+       // options is an array of "inputOptions" objects with an additional
+       // "output" property that contains an array of "outputOptions".
+       // We generate a single output so the array only has one element.
+       const {
+               options: [ optionsObj ],
+               warnings
+       } = await loadConfigFile( configPath, {} );
+
+       // "warnings" wraps the default `onwarn` handler passed by the CLI.
+       // This prints all warnings up to this point:
+       warnings.flush();
+
+       const bundle = await rollup( optionsObj );
+       await Promise.all( optionsObj.output.map( bundle.write ) );
+
+       console.log( `Build completed: Rollup, version: ${ name }` );
+}
+
+export async function runRollupPureEsm() {
+       await runRollup( "pure ESM", pureEsmConfigPath );
+}
+
+export async function runRollupEsmAndCommonJs() {
+       await runRollup( "ESM + CommonJS", commonJSConfigPath );
+}
diff --git a/test/bundler_smoke_tests/lib/run-webpack.js b/test/bundler_smoke_tests/lib/run-webpack.js
new file mode 100644 (file)
index 0000000..ebbaaec
--- /dev/null
@@ -0,0 +1,26 @@
+import webpack from "webpack";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+const configPath = path.resolve( dirname, "..", "webpack.config.cjs" );
+
+// See https://webpack.js.org/api/node/#webpack
+export async function runWebpack() {
+       return new Promise( async( resolve, reject ) => {
+               console.log( "Running Webpack" );
+
+               const { default: config } = await import( configPath );
+
+               webpack( config, ( err, stats ) => {
+                       if ( err || stats.hasErrors() ) {
+                               console.error( "Errors detected during Webpack compilation" );
+                               reject( err );
+                               return;
+                       }
+
+                       console.log( "Build completed: Webpack" );
+                       resolve();
+               } );
+       } );
+}
diff --git a/test/bundler_smoke_tests/lib/utils.js b/test/bundler_smoke_tests/lib/utils.js
new file mode 100644 (file)
index 0000000..0b960db
--- /dev/null
@@ -0,0 +1,13 @@
+import fs from "node:fs/promises";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+const TMP_BUNDLERS_DIR = path.resolve( dirname, "..", "tmp" );
+
+export async function cleanTmpBundlersDir() {
+       await fs.rm( TMP_BUNDLERS_DIR, {
+               force: true,
+               recursive: true
+       } );
+}
diff --git a/test/bundler_smoke_tests/rollup-commonjs.config.js b/test/bundler_smoke_tests/rollup-commonjs.config.js
new file mode 100644 (file)
index 0000000..3060d23
--- /dev/null
@@ -0,0 +1,19 @@
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import resolve from "@rollup/plugin-node-resolve";
+import commonjs from "@rollup/plugin-commonjs";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+
+export default {
+       input: `${ dirname }/src-esm-commonjs/main.js`,
+       output: {
+               dir: `${ dirname }/tmp/rollup-commonjs`,
+               format: "iife",
+               sourcemap: true
+       },
+       plugins: [
+               resolve(),
+               commonjs()
+       ]
+};
diff --git a/test/bundler_smoke_tests/rollup-pure-esm.config.js b/test/bundler_smoke_tests/rollup-pure-esm.config.js
new file mode 100644 (file)
index 0000000..7476e7b
--- /dev/null
@@ -0,0 +1,17 @@
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import resolve from "@rollup/plugin-node-resolve";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+
+export default {
+       input: `${ dirname }/src-pure-esm/main.js`,
+       output: {
+               dir: `${ dirname }/tmp/rollup-pure-esm`,
+               format: "iife",
+               sourcemap: true
+       },
+       plugins: [
+               resolve()
+       ]
+};
diff --git a/test/bundler_smoke_tests/run-jsdom-tests.js b/test/bundler_smoke_tests/run-jsdom-tests.js
new file mode 100644 (file)
index 0000000..ba7100c
--- /dev/null
@@ -0,0 +1,73 @@
+import fs from "node:fs/promises";
+import jsdom, { JSDOM } from "jsdom";
+import path from "node:path";
+import { fileURLToPath } from "node:url";
+import { runRollupEsmAndCommonJs, runRollupPureEsm } from "./lib/run-rollup.js";
+import { runWebpack } from "./lib/run-webpack.js";
+import { cleanTmpBundlersDir } from "./lib/utils.js";
+
+const dirname = path.dirname( fileURLToPath( import.meta.url ) );
+
+async function runJSDOMTest( { title, folder } ) {
+       console.log( "Running bundlers tests:", title );
+
+       const template = await fs.readFile( `${ dirname }/test.html`, "utf-8" );
+       const scriptSource = await fs.readFile(
+               `${ dirname }/tmp/${ folder }/main.js`, "utf-8" );
+
+       const html = template
+               .replace( /@TITLE\b/, () => title )
+               .replace( /@SCRIPT\b/, () => scriptSource );
+
+       const virtualConsole = new jsdom.VirtualConsole();
+       virtualConsole.sendTo( console );
+       virtualConsole.on( "assert", ( success, message ) => {
+               if ( !success ) {
+                       process.exitCode = 1;
+               }
+       } );
+
+       new JSDOM( html, {
+               resources: "usable",
+               runScripts: "dangerously",
+               virtualConsole
+       } );
+
+       if ( process.exitCode === 0 || process.exitCode == null ) {
+               console.log( "Bundlers tests passed for:", title );
+       } else {
+               console.error( "Bundlers tests failed for:", title );
+       }
+}
+
+async function buildAndTest() {
+       await cleanTmpBundlersDir();
+
+       await Promise.all( [
+               runRollupPureEsm(),
+               runRollupEsmAndCommonJs(),
+               runWebpack()
+       ] );
+
+       await Promise.all( [
+               runJSDOMTest( {
+                       title: "Rollup with pure ESM setup",
+                       folder: "rollup-pure-esm"
+               } ),
+
+               runJSDOMTest( {
+                       title: "Rollup with ESM + CommonJS",
+                       folder: "rollup-commonjs"
+               } ),
+
+               runJSDOMTest( {
+                       title: "Webpack",
+                       folder: "webpack"
+               } )
+       ] );
+
+       // The directory won't be cleaned in case of failures; this may aid debugging.
+       await cleanTmpBundlersDir();
+}
+
+await buildAndTest();
diff --git a/test/bundler_smoke_tests/src-esm-commonjs/jquery-require.cjs b/test/bundler_smoke_tests/src-esm-commonjs/jquery-require.cjs
new file mode 100644 (file)
index 0000000..7da6dc4
--- /dev/null
@@ -0,0 +1,12 @@
+"use strict";
+
+const $ = require( "jquery" );
+const $slim = require( "jquery/slim" );
+
+const { jQueryFactory } = require( "jquery/factory" );
+const { jQueryFactory: jQueryFactorySlim } = require( "jquery/factory-slim" );
+
+module.exports.$required = $;
+module.exports.$slimRequired = $slim;
+module.exports.jQueryFactoryRequired = jQueryFactory;
+module.exports.jQueryFactorySlimRequired = jQueryFactorySlim;
diff --git a/test/bundler_smoke_tests/src-esm-commonjs/main.js b/test/bundler_smoke_tests/src-esm-commonjs/main.js
new file mode 100644 (file)
index 0000000..2ea6da1
--- /dev/null
@@ -0,0 +1,38 @@
+import { $ as $imported } from "jquery";
+import { $ as $slimImported } from "jquery/slim";
+
+import { jQueryFactory as jQueryFactoryImported } from "jquery/factory";
+import { jQueryFactory as jQueryFactorySlimImported } from "jquery/factory-slim";
+
+import {
+       $required,
+       $slimRequired,
+       jQueryFactoryRequired,
+       jQueryFactorySlimRequired
+} from "./jquery-require.cjs";
+
+console.assert( $required === $imported,
+       "Only one copy of full jQuery should exist" );
+console.assert( /^jQuery/.test( $imported.expando ),
+       "jQuery.expando should be detected on full jQuery" );
+
+console.assert( $slimRequired === $slimImported,
+       "Only one copy of slim jQuery should exist" );
+console.assert( /^jQuery/.test( $slimImported.expando ),
+       "jQuery.expando should be detected on slim jQuery" );
+
+console.assert( jQueryFactoryImported === jQueryFactoryRequired,
+       "Only one copy of full jQueryFactory should exist" );
+console.assert( !( "expando" in jQueryFactoryImported ),
+       "jQuery.expando should not be attached to the full factory" );
+const $fromFactory = jQueryFactoryImported( window );
+console.assert( /^jQuery/.test( $fromFactory.expando ),
+       "jQuery.expando should be detected on full jQuery from factory" );
+
+console.assert( jQueryFactorySlimImported === jQueryFactorySlimRequired,
+       "Only one copy of slim jQueryFactory should exist" );
+console.assert( !( "expando" in jQueryFactorySlimImported ),
+       "jQuery.expando should not be attached to the slim factory" );
+const $fromFactorySlim = jQueryFactorySlimImported( window );
+console.assert( /^jQuery/.test( $fromFactorySlim.expando ),
+       "jQuery.expando should be detected on slim jQuery from factory" );
diff --git a/test/bundler_smoke_tests/src-pure-esm/main.js b/test/bundler_smoke_tests/src-pure-esm/main.js
new file mode 100644 (file)
index 0000000..9e6cbf7
--- /dev/null
@@ -0,0 +1,22 @@
+import { $ } from "jquery";
+import { $ as $slim } from "jquery/slim";
+
+import { jQueryFactory } from "jquery/factory";
+import { jQueryFactory as jQueryFactorySlim } from "jquery/factory-slim";
+
+console.assert( /^jQuery/.test( $.expando ),
+       "jQuery.expando should be detected on full jQuery" );
+console.assert( /^jQuery/.test( $slim.expando ),
+       "jQuery.expando should be detected on slim jQuery" );
+
+console.assert( !( "expando" in jQueryFactory ),
+       "jQuery.expando should not be attached to the full factory" );
+const $fromFactory = jQueryFactory( window );
+console.assert( /^jQuery/.test( $fromFactory.expando ),
+       "jQuery.expando should be detected on full jQuery from factory" );
+
+console.assert( !( "expando" in jQueryFactorySlim ),
+       "jQuery.expando should not be attached to the slim factory" );
+const $fromFactorySlim = jQueryFactorySlim( window );
+console.assert( /^jQuery/.test( $fromFactorySlim.expando ),
+       "jQuery.expando should be detected on slim jQuery from factory" );
diff --git a/test/bundler_smoke_tests/test.html b/test/bundler_smoke_tests/test.html
new file mode 100644 (file)
index 0000000..fa1795b
--- /dev/null
@@ -0,0 +1,11 @@
+<!doctype html>
+<html>
+<head lang='en'>
+       <meta charset='utf-8'>
+       <meta name='viewport' content='width=device-width'>
+       <title>Bundlers tests: @TITLE</title>
+</head>
+<body>
+<script>@SCRIPT</script>
+</body>
+</html>
diff --git a/test/bundler_smoke_tests/webpack.config.cjs b/test/bundler_smoke_tests/webpack.config.cjs
new file mode 100644 (file)
index 0000000..7ea427e
--- /dev/null
@@ -0,0 +1,9 @@
+"use strict";
+
+module.exports = {
+       entry: `${ __dirname }/src-esm-commonjs/main.js`,
+       output: {
+               filename: "main.js",
+               path: `${ __dirname }/tmp/webpack`
+       }
+};
index e079912d8d4a6df9f5146cda3d8a8e9137380e33..2587c9989acad0f16b36a44827ab72092909e00e 100644 (file)
@@ -1,6 +1,6 @@
 "use strict";
 
-const assert = require( "node:assert" );
+const assert = require( "node:assert/strict" );
 
 const { ensureGlobalNotCreated } = require( "../lib/ensure_global_not_created.cjs" );
 const { getJQueryModuleSpecifier } = require( "../lib/jquery-module-specifier.cjs" );
index 5eee11d216c8c8315ede19839689f41f21d0fe34..de27739ebdfb951c6529ff72c93ddc4144075cb1 100644 (file)
@@ -1,6 +1,6 @@
 "use strict";
 
-const assert = require( "node:assert" );
+const assert = require( "node:assert/strict" );
 
 // Ensure the jQuery property on global/window/module.exports/etc. was not
 // created in a CommonJS environment.
index 01e0d4b5600189c3fab8e951576cb9737ebd969c..1226970e452e62be65101fb488eb2fb8fcc952bb 100644 (file)
@@ -1,6 +1,6 @@
 "use strict";
 
-const assert = require( "node:assert" );
+const assert = require( "node:assert/strict" );
 const { JSDOM } = require( "jsdom" );
 
 const { ensureJQuery } = require( "./ensure_jquery.cjs" );
index be23e990060d7e5851153850a07d55ed9b8186aa..cbca14032608054882ebaffe24e02d15cc063fc0 100644 (file)
@@ -1,6 +1,6 @@
 "use strict";
 
-const assert = require( "node:assert" );
+const assert = require( "node:assert/strict" );
 
 // Check if the object we got is the jQuery object by invoking a basic API.
 const ensureJQuery = ( jQuery ) => {
diff --git a/test/node_smoke_tests/dual/factory/import-and-require-factory.js b/test/node_smoke_tests/dual/factory/import-and-require-factory.js
new file mode 100644 (file)
index 0000000..c94ae37
--- /dev/null
@@ -0,0 +1,17 @@
+import assert from "node:assert/strict";
+import { JSDOM } from "jsdom";
+
+const { window } = new JSDOM( "" );
+
+const { jQueryFactory: factoryImported } = await import( process.argv[ 2 ] );
+const { jQueryFactory: factoryRequired } = await import( "../lib/jquery-require-factory.cjs" );
+
+assert( factoryImported === factoryRequired,
+       "More than one copy of jQueryFactory exists" );
+
+assert( !( "expando" in factoryImported ),
+       "jQuery.expando should not be attached to the factory" );
+
+const $ = factoryImported( window );
+
+assert( /^jQuery/.test( $.expando ), "jQuery.expando should be detected" );
diff --git a/test/node_smoke_tests/dual/lib/jquery-require-factory.cjs b/test/node_smoke_tests/dual/lib/jquery-require-factory.cjs
new file mode 100644 (file)
index 0000000..55855b5
--- /dev/null
@@ -0,0 +1,5 @@
+"use strict";
+
+const { jQueryFactory } = require( process.argv[ 2 ] );
+
+module.exports.jQueryFactory = jQueryFactory;
diff --git a/test/node_smoke_tests/dual/lib/jquery-require.cjs b/test/node_smoke_tests/dual/lib/jquery-require.cjs
new file mode 100644 (file)
index 0000000..7b46721
--- /dev/null
@@ -0,0 +1,5 @@
+"use strict";
+
+const $ = require( process.argv[ 2 ] );
+
+module.exports.$ = $;
diff --git a/test/node_smoke_tests/dual/regular/import-and-require.js b/test/node_smoke_tests/dual/regular/import-and-require.js
new file mode 100644 (file)
index 0000000..2b958a2
--- /dev/null
@@ -0,0 +1,13 @@
+import assert from "node:assert/strict";
+import { JSDOM } from "jsdom";
+
+const { window } = new JSDOM( "" );
+
+// Set the window global.
+globalThis.window = window;
+
+const { $: $imported } = await import( process.argv[ 2 ] );
+const { $: $required } = await import( "../lib/jquery-require.cjs" );
+
+assert( $imported === $required, "More than one copy of jQuery exists" );
+assert( /^jQuery/.test( $imported.expando ), "jQuery.expando should be detected" );
index ccb3383adbc9657ef1abbb2f36f26547800a7765..b902d2913371db17ba88c6029a167ed5c6d246cc 100644 (file)
@@ -1,4 +1,4 @@
-import assert from "node:assert";
+import assert from "node:assert/strict";
 
 import { ensureGlobalNotCreated } from "../lib/ensure_global_not_created.js";
 import { getJQueryModuleSpecifier } from "../lib/jquery-module-specifier.js";
index d7648bd68627ffa5c9c757c5814b0170500f5ec8..caccd82e36a2f36fe44318edfc91b21a3fc89520 100644 (file)
@@ -1,4 +1,4 @@
-import assert from "node:assert";
+import assert from "node:assert/strict";
 
 // Ensure the jQuery property on global/window/module "this"/etc. was not
 // created in a CommonJS environment.
index 3f88913d07744474dc3eff521d01fd64bf31b991..c12e58c59f7d7ee38eac06d43d4bd2c3e9268ed7 100644 (file)
@@ -1,4 +1,4 @@
-import assert from "node:assert";
+import assert from "node:assert/strict";
 const { JSDOM } = await import( "jsdom" );
 
 const { ensureJQuery } = await import( "./ensure_jquery.js" );
index d07624ebd2528adb41e134ac56d90670c9e36fbf..13749306ea66e93d0f0cb1d47fe61b3475e82d82 100644 (file)
@@ -1,4 +1,4 @@
-import assert from "node:assert";
+import assert from "node:assert/strict";
 
 // Check if the object we got is the jQuery object by invoking a basic API.
 export const ensureJQuery = ( jQuery ) => {
index ac5a416c858032335a35e0cf8529472dd083acab..fee3ca5aefac55a6cc54ac7d944d980d17e99c63 100644 (file)
@@ -11,7 +11,7 @@ const { window } = new JSDOM( "" );
 // Set the window global.
 globalThis.window = window;
 
-const { default: jQuery } = await import( jQueryModuleSpecifier );
+const { jQuery } = await import( jQueryModuleSpecifier );
 
 ensureJQuery( jQuery );
 ensureGlobalNotCreated( window );