jenkins-bot has submitted this change and it was merged.

Change subject: resourceloader: Implement modern module loading (1/2)
......................................................................


resourceloader: Implement modern module loading (1/2)

This defines mw.loader.require() and 'module.exports'. These will
be exposed to mw.loader.implement() closures as local 'require'
and 'module' parameters.

Changes:
* This alters nestedAddScript to maintain a single queue to
  ensure scripts from different modules are never downloaded in
  parallel (used in debug mode).

Note:
A further patch will start passing module and require to module definitions.

Bug: T108655
Change-Id: Ia925844cc22f143f531216f2fe3efead08885b5d
---
M .jshintrc
M resources/src/mediawiki/mediawiki.js
M tests/qunit/suites/resources/mediawiki/mediawiki.test.js
3 files changed, 115 insertions(+), 3 deletions(-)

Approvals:
  Krinkle: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/.jshintrc b/.jshintrc
index 62b9d82..441c4e3 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -20,6 +20,8 @@
        "browser": true,
 
        "globals": {
+               "require": false,
+               "module": false,
                "mediaWiki": true,
                "JSON": true,
                "OO": true,
diff --git a/resources/src/mediawiki/mediawiki.js 
b/resources/src/mediawiki/mediawiki.js
index 2aada9e..f282db6 100644
--- a/resources/src/mediawiki/mediawiki.js
+++ b/resources/src/mediawiki/mediawiki.js
@@ -714,6 +714,7 @@
                         *             'group': 'somegroup', (or) null
                         *             'source': 'local', (or) 'anotherwiki'
                         *             'skip': 'return !!window.Example', (or) 
null
+                        *             'module': export Object
                         *
                         *             // Set from execute() or 
mw.loader.state()
                         *             'state': 'registered', 'loaded', 
'loading', 'ready', 'error', or 'missing'
@@ -766,6 +767,10 @@
 
                                // List of modules which will be loaded as when 
ready
                                batch = [],
+
+                               // Pending queueModuleScript() requests
+                               handlingPendingRequests = false,
+                               pendingRequests = [],
 
                                // List of modules to be loaded
                                queue = [],
@@ -1177,6 +1182,43 @@
                        }
 
                        /**
+                        * Queue the loading and execution of a script for a 
particular module.
+                        *
+                        * @private
+                        * @param {string} src URL of the script
+                        * @param {string} [moduleName] Name of currently 
executing module
+                        * @return {jQuery.Promise}
+                        */
+                       function queueModuleScript( src, moduleName ) {
+                               var r = $.Deferred();
+
+                               pendingRequests.push( function () {
+                                       if ( moduleName && !hasOwn.call( 
registry, moduleName ) ) {
+                                               window.require = 
mw.loader.require;
+                                               window.module = registry[ 
moduleName ].module;
+                                       }
+                                       addScript( src ).always( function () {
+                                               // Clear environment
+                                               delete window.require;
+                                               delete window.module;
+                                               r.resolve();
+
+                                               // Start the next one (if any)
+                                               if ( pendingRequests[ 0 ] ) {
+                                                       
pendingRequests.shift()();
+                                               } else {
+                                                       handlingPendingRequests 
= false;
+                                               }
+                                       } );
+                               } );
+                               if ( !handlingPendingRequests && 
pendingRequests[ 0 ] ) {
+                                       handlingPendingRequests = true;
+                                       pendingRequests.shift()();
+                               }
+                               return r.promise();
+                       }
+
+                       /**
                         * Utility function for execute()
                         *
                         * @ignore
@@ -1226,7 +1268,7 @@
                                                        handlePending( module );
                                                };
                                                nestedAddScript = function ( 
arr, callback, i ) {
-                                                       // Recursively call 
addScript() in its own callback
+                                                       // Recursively call 
queueModuleScript() in its own callback
                                                        // for each element of 
arr.
                                                        if ( i >= arr.length ) {
                                                                // We're at the 
end of the array
@@ -1234,7 +1276,7 @@
                                                                return;
                                                        }
 
-                                                       addScript( arr[ i ] 
).always( function () {
+                                                       queueModuleScript( arr[ 
i ], module ).always( function () {
                                                                
nestedAddScript( arr, callback, i + 1 );
                                                        } );
                                                };
@@ -1249,8 +1291,9 @@
                                                        } else if ( 
$.isFunction( script ) ) {
                                                                // Pass jQuery 
twice so that the signature of the closure which wraps
                                                                // the script 
can bind both '$' and 'jQuery'.
-                                                               script( $, $ );
+                                                               script( $, $, 
mw.loader.require, registry[ module ].module );
                                                                
markModuleReady();
+
                                                        } else if ( typeof 
script === 'string' ) {
                                                                // Site and 
user modules are legacy scripts that run in the global scope.
                                                                // This is 
transported as a string instead of a function to avoid needing
@@ -1742,6 +1785,11 @@
                                        }
                                        // List the module as registered
                                        registry[ module ] = {
+                                               // Exposed to execute() for 
mw.loader.implement() closures.
+                                               // Import happens via require().
+                                               module: {
+                                                       exports: {}
+                                               },
                                                version: version !== undefined 
? String( version ) : '',
                                                dependencies: [],
                                                group: typeof group === 
'string' ? group : null,
@@ -2010,6 +2058,26 @@
                                },
 
                                /**
+                                * Get the exported value of a module.
+                                *
+                                * Module provide this value via their local 
`module.exports`.
+                                *
+                                * @since 1.27
+                                * @return {Array}
+                                */
+                               require: function ( moduleName ) {
+                                       var state = mw.loader.getState( 
moduleName );
+
+                                       // Only ready mudules can be required
+                                       if ( state !== 'ready' ) {
+                                               // Module may've forgotten to 
declare a dependency
+                                               throw new Error( 'Module "' + 
moduleName + '" is not loaded.' );
+                                       }
+
+                                       return registry[ moduleName 
].module.exports;
+                               },
+
+                               /**
                                 * @inheritdoc mw.inspect#runReports
                                 * @method
                                 */
diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js 
b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js
index fe5530b..ce4ea8b 100644
--- a/tests/qunit/suites/resources/mediawiki/mediawiki.test.js
+++ b/tests/qunit/suites/resources/mediawiki/mediawiki.test.js
@@ -1085,4 +1085,46 @@
                );
        } );
 
+       QUnit.test( 'mw.loader.require', 6, function ( assert ) {
+               var module1, module2, module3, module4;
+
+               mw.loader.register( [
+                       [ 'test.module.require1', '0' ],
+                       [ 'test.module.require2', '0' ],
+                       [ 'test.module.require3', '0' ],
+                       [ 'test.module.require4', '0', [ 'test.module.require3' 
] ]
+               ] );
+               mw.loader.implement( 'test.module.require1', function () {} );
+               mw.loader.implement( 'test.module.require2', function ( $, 
jQuery, require, module ) {
+                       module.exports = 1;
+               } );
+               mw.loader.implement( 'test.module.require3', function ( $, 
jQuery, require, module ) {
+                       module.exports = function () {
+                               return 'hello world';
+                       };
+               } );
+               mw.loader.implement( 'test.module.require4', function ( $, 
jQuery, require, module ) {
+                       var other = require( 'test.module.require3' );
+                       module.exports = {
+                               pizza: function () {
+                                       return other();
+                               }
+                       };
+               } );
+               module1 = mw.loader.require( 'test.module.require1' );
+               module2 = mw.loader.require( 'test.module.require2' );
+               module3 = mw.loader.require( 'test.module.require3' );
+               module4 = mw.loader.require( 'test.module.require4' );
+
+               assert.strictEqual( typeof module1, 'object', 'export of module 
with no export' );
+               assert.strictEqual( module2, 1, 'export a number' );
+               assert.strictEqual( module3(), 'hello world', 'export a 
function' );
+               assert.strictEqual( typeof module4.pizza, 'function', 'export 
an object' );
+               assert.strictEqual( module4.pizza(), 'hello world', 'module can 
require other modules' );
+
+               assert.throws( function () {
+                       mw.loader.require( '_badmodule' );
+               }, /is not loaded/, 'Requesting non-existent modules throws 
error.' );
+       } );
+
 }( mediaWiki, jQuery ) );

-- 
To view, visit https://gerrit.wikimedia.org/r/260071
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ia925844cc22f143f531216f2fe3efead08885b5d
Gerrit-PatchSet: 36
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Jdlrobson <[email protected]>
Gerrit-Reviewer: AndyRussG <[email protected]>
Gerrit-Reviewer: Bartosz DziewoƄski <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Edokter <[email protected]>
Gerrit-Reviewer: Jack Phoenix <[email protected]>
Gerrit-Reviewer: Jdlrobson <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to