From f37c2e51f36c8f8bab3879064a90e86a685feafc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Go=C5=82=C4=99biowski-Owczarek?= Date: Mon, 9 Dec 2019 20:00:44 +0100 Subject: [PATCH] Build: Auto-convert sources to AMD jQuery source has been migrated in gh-4541 from AMD to ES modules. To maintain support for consumers of our AMD modules, this commits adds a task transpiling the ES modules sources in `src/` to AMD in `amd/`. A "Load with AMD" checkbox was also restored to the QUnit setup. Note that, contrary to jQuery 3.x, AMD files need to be generated via `grunt amd` or `grunt` as sources are not authored in ECMAScript modules. To achieve a similar no-compile experience during jQuery 4.x testing, use the new "Load as modules" checkbox which works in all supported browsers except for IE & Edge (the legacy, EdgeHTML-based one). Ref gh-4541 Closes gh-4554 --- .eslintignore | 2 +- .gitignore | 2 ++ Gruntfile.js | 2 ++ build/release.js | 15 ++++++++++----- build/release/dist.js | 1 + build/tasks/amd.js | 43 +++++++++++++++++++++++++++++++++++++++++++ package.json | 3 ++- test/data/testinit.js | 12 +++++++----- test/index.html | 4 ++-- test/jquery.js | 23 +++++++++++++++++++++-- 10 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 build/tasks/amd.js diff --git a/.eslintignore b/.eslintignore index 3ee82bba3..61eddeb35 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ -external +amd node_modules *.min.js dist/** diff --git a/.gitignore b/.gitignore index c00c4ac7e..a6685904e 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ npm-debug.log* /dist/* !/dist/.eslintrc.json +/amd + /node_modules /test/data/core/jquery-iterability-transpiled.js diff --git a/Gruntfile.js b/Gruntfile.js index 9ed250a3e..351700743 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -178,6 +178,7 @@ module.exports = function( grunt ) { { pattern: "dist/jquery.*", included: false, served: true }, { pattern: "src/**", type: "module", included: false, served: true }, + { pattern: "amd/**", included: false, served: true }, { pattern: "node_modules/**", included: false, served: true }, { pattern: "test/**/*.@(js|css|jpg|html|xml|svg)", @@ -319,6 +320,7 @@ module.exports = function( grunt ) { grunt.registerTask( "default", [ "eslint:dev", "build:*:*", + "amd", "uglify", "remove_map_comment", "dist:*", diff --git a/build/release.js b/build/release.js index 6011066ff..f463d8e40 100644 --- a/build/release.js +++ b/build/release.js @@ -22,18 +22,23 @@ module.exports = function( Release ) { npmTags = Release.npmTags; + function setSrcVersion( filepath ) { + var contents = fs.readFileSync( filepath, "utf8" ); + contents = contents.replace( /@VERSION/g, Release.newVersion ); + fs.writeFileSync( filepath, contents, "utf8" ); + } + Release.define( { npmPublish: true, issueTracker: "github", /** - * Set the version in the src folder for distributing AMD + * Set the version in the src folder for distributing ES modules + * and in the amd folder for AMD. */ _setSrcVersion: function() { - var corePath = __dirname + "/../src/core.js", - contents = fs.readFileSync( corePath, "utf8" ); - contents = contents.replace( /@VERSION/g, Release.newVersion ); - fs.writeFileSync( corePath, contents, "utf8" ); + setSrcVersion( `${ __dirname }/../src/core.js` ); + setSrcVersion( `${ __dirname }/../amd/core.js` ); }, /** diff --git a/build/release/dist.js b/build/release/dist.js index 0ca396811..e2b1c5fb4 100644 --- a/build/release/dist.js +++ b/build/release/dist.js @@ -13,6 +13,7 @@ module.exports = function( Release, files, complete ) { // These files are included with the distribution extras = [ + "amd", "src", "LICENSE.txt", "AUTHORS.txt", diff --git a/build/tasks/amd.js b/build/tasks/amd.js new file mode 100644 index 000000000..617773ff2 --- /dev/null +++ b/build/tasks/amd.js @@ -0,0 +1,43 @@ +/** + * Compiles sources from ES Modules in `src/` to AMD in `amd/`. + */ + +"use strict"; + +module.exports = function( grunt ) { + const path = require( "path" ); + const rimraf = require( "rimraf" ); + const rollup = require( "rollup" ); + const srcFolder = path.resolve( __dirname, "..", "..", "src" ); + const amdFolder = path.resolve( srcFolder, "..", "amd" ); + const inputFileName = "jquery.js"; + + const inputRollupOptions = { + input: path.resolve( srcFolder, inputFileName ), + preserveModules: true + }; + + const outputRollupOptions = { + format: "amd", + dir: "amd" + }; + + grunt.registerTask( + "amd", + "Convert ES modules from `src/` to AMD modules in `amd/`", + async function() { + const done = this.async(); + + try { + grunt.verbose.writeln( "Removing the 'amd' directory..." ); + rimraf( amdFolder, async function() { + const bundle = await rollup.rollup( inputRollupOptions ); + await bundle.write( outputRollupOptions ); + grunt.log.ok( "Sources from 'src' converted to AMD in 'amd'." ); + done(); + } ); + } catch ( err ) { + done( err ); + } + } ); +}; diff --git a/package.json b/package.json index 754ac08b5..abfee2589 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,8 @@ "qunit": "2.9.2", "raw-body": "2.3.3", "requirejs": "2.3.6", - "rollup": "1.25.2", + "rimraf": "3.0.0", + "rollup": "1.27.6", "sinon": "7.3.1", "strip-json-comments": "2.0.1", "testswarm": "1.1.0", diff --git a/test/data/testinit.js b/test/data/testinit.js index 7a8697189..4088e4671 100644 --- a/test/data/testinit.js +++ b/test/data/testinit.js @@ -299,14 +299,16 @@ QUnit.testUnlessIE = QUnit.isIE ? QUnit.skip : QUnit.test; this.loadTests = function() { - // Directly load tests that need synchronous evaluation - if ( !QUnit.urlParams.esmodules || document.readyState === "loading" ) { + // QUnit.config is populated from QUnit.urlParams but only at the beginning + // of the test run. We need to read both. + var amd = QUnit.config.amd || QUnit.urlParams.amd; + + // Directly load tests that need evaluation before DOMContentLoaded. + if ( !amd || document.readyState === "loading" ) { document.write( " - + @@ -29,7 +29,7 @@ // Load tests if they have not been loaded // This is in a different script tag to ensure that // jQuery is on the page when the testrunner executes - if ( !QUnit.urlParams.esmodules ) { + if ( !QUnit.urlParams.esmodules && !QUnit.urlParams.amd ) { loadTests(); } diff --git a/test/jquery.js b/test/jquery.js index d6d53fb26..c34c7c491 100644 --- a/test/jquery.js +++ b/test/jquery.js @@ -28,7 +28,12 @@ QUnit.config.urlConfig.push( { id: "esmodules", label: "Load as modules", - tooltip: "Load a relevant jQuery module file (and its dependencies)" + tooltip: "Load the jQuery module file (and its dependencies)" + } ); + QUnit.config.urlConfig.push( { + id: "amd", + label: "Load with AMD", + tooltip: "Load the AMD jQuery file (and its dependencies)" } ); } @@ -39,7 +44,7 @@ } ); } - // Honor AMD loading on the main window (detected by seeing QUnit on it). + // Honor ES modules loading on the main window (detected by seeing QUnit on it). // This doesn't apply to iframes because they synchronously expect jQuery to be there. if ( urlParams.esmodules && window.QUnit ) { @@ -57,6 +62,20 @@ eval( dynamicImportSource ); + // Apply similar treatment for AMD modules + } else if ( urlParams.amd && window.QUnit ) { + require.config( { + baseUrl: parentUrl + } ); + src = "amd/jquery"; + + // Include tests if specified + if ( typeof loadTests !== "undefined" ) { + require( [ src ], loadTests ); + } else { + require( [ src ] ); + } + // Otherwise, load synchronously } else { document.write( "