Skip to content

Commit

Permalink
Build: Auto-convert sources to AMD
Browse files Browse the repository at this point in the history
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
  • Loading branch information
mgol committed Dec 9, 2019
1 parent d5c505e commit f37c2e5
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
external
amd
node_modules
*.min.js
dist/**
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ npm-debug.log*
/dist/*
!/dist/.eslintrc.json

/amd

/node_modules

/test/data/core/jquery-iterability-transpiled.js
2 changes: 2 additions & 0 deletions Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down Expand Up @@ -319,6 +320,7 @@ module.exports = function( grunt ) {
grunt.registerTask( "default", [
"eslint:dev",
"build:*:*",
"amd",
"uglify",
"remove_map_comment",
"dist:*",
Expand Down
15 changes: 10 additions & 5 deletions build/release.js
Original file line number Diff line number Diff line change
Expand Up @@ -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` );
},

/**
Expand Down
1 change: 1 addition & 0 deletions build/release/dist.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = function( Release, files, complete ) {

// These files are included with the distribution
extras = [
"amd",
"src",
"LICENSE.txt",
"AUTHORS.txt",
Expand Down
43 changes: 43 additions & 0 deletions build/tasks/amd.js
Original file line number Diff line number Diff line change
@@ -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 );
}
} );
};
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
12 changes: 7 additions & 5 deletions test/data/testinit.js
Original file line number Diff line number Diff line change
Expand Up @@ -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( "<script src='" + parentUrl + "test/unit/ready.js'><\x2Fscript>" );
} else {
QUnit.module( "ready", function() {
QUnit.test( "jQuery ready", function( assert ) {
assert.ok( false, "Test should be initialized before DOM ready" );
} );
QUnit.skip( "jQuery ready tests skipped in async mode", function() {} );
} );
}

Expand Down
4 changes: 2 additions & 2 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<!-- See testinit for the list of tests -->
<script src="data/testinit.js"></script>

<!-- A script that includes jQuery min, dev, or ES modules -->
<!-- A script that includes jQuery min, dev, ES modules or AMD -->
<!-- Adds "basic" URL option, even to iframes -->
<!-- iframes will not load AMD as loading needs to be synchronous for some tests -->
<!-- Also executes the function above to load tests -->
Expand All @@ -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();
}
</script>
Expand Down
23 changes: 21 additions & 2 deletions test/jquery.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)"
} );
}

Expand All @@ -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 ) {

Expand All @@ -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( "<script id='jquery-js' nonce='jquery+hardcoded+nonce' src='" + parentUrl + src + "'><\x2Fscript>" );
Expand Down

0 comments on commit f37c2e5

Please sign in to comment.