X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=resources%2Fsrc%2Fmediawiki%2Fmediawiki.js;h=18f7f0abda7b33e04e1db6d4884ef75c32b27bec;hb=33eabfd8d6a738ae3ed13e3f52c0bbd7664e581a;hp=86a9a0af1b4ba80546d9210ded417dac8b63eb23;hpb=39fb8a4f531256e122fa4c01d4417d23d168f299;p=lhc%2Fweb%2Fwiklou.git diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js index 86a9a0af1b..18f7f0abda 100644 --- a/resources/src/mediawiki/mediawiki.js +++ b/resources/src/mediawiki/mediawiki.js @@ -754,6 +754,7 @@ * is used) * - load-callback: exception thrown by user callback * - module-execute: exception thrown by module code + * - resolve: failed to sort dependencies for a module in mw.loader.load * - store-eval: could not evaluate module code cached in localStorage * - store-localstorage-init: localStorage or JSON parse error in mw.loader.store.init * - store-localstorage-json: JSON conversion error in mw.loader.store.set @@ -1169,6 +1170,33 @@ return resolved; } + /** + * Like #resolve(), except it will silently ignore modules that + * are missing or have missing dependencies. + * + * @private + * @param {string[]} modules Array of string module names + * @return {Array} List of dependencies. + */ + function resolveStubbornly( modules ) { + var i, saved, resolved = []; + for ( i = 0; i < modules.length; i++ ) { + saved = resolved.slice(); + try { + sortDependencies( modules[ i ], resolved ); + } catch ( err ) { + // This module is unknown or has unknown dependencies. + // Undo any incomplete resolutions made and keep going. + resolved = saved; + mw.track( 'resourceloader.exception', { + exception: err, + source: 'resolve' + } ); + } + } + return resolved; + } + /** * Load and execute a script. * @@ -1270,10 +1298,7 @@ registry[ module ].state = 'executing'; runScript = function () { - var script, markModuleReady, nestedAddScript, legacyWait, implicitDependencies, - // Expand to include dependencies since we have to exclude both legacy modules - // and their dependencies from the legacyWait (to prevent a circular dependency). - legacyModules = resolve( mw.config.get( 'wgResourceLoaderLegacyModules', [] ) ); + var script, markModuleReady, nestedAddScript, implicitDependencies, implicitWait; script = registry[ module ].script; markModuleReady = function () { @@ -1294,9 +1319,7 @@ } ); }; - implicitDependencies = ( $.inArray( module, legacyModules ) !== -1 ) ? - [] : - legacyModules; + implicitDependencies = []; if ( module === 'user' ) { // Implicit dependency on the site module. Not real dependency because @@ -1304,11 +1327,11 @@ implicitDependencies.push( 'site' ); } - legacyWait = implicitDependencies.length ? + implicitWait = implicitDependencies.length ? mw.loader.using( implicitDependencies ) : $.Deferred().resolve(); - legacyWait.always( function () { + implicitWait.always( function () { try { if ( Array.isArray( script ) ) { nestedAddScript( script, markModuleReady, 0 ); @@ -2017,6 +2040,15 @@ /** * Load an external script or one or more modules. * + * This method takes a list of unrelated modules. Use cases: + * + * - A web page will be composed of many different widgets. These widgets independently + * queue their ResourceLoader modules (`OutputPage::addModules()`). If any of them + * have problems, or are no longer known (e.g. cached HTML), the other modules + * should still be loaded. + * - This method is used for preloading, which must not throw. Later code that + * calls #using() will handle the error. + * * @param {string|Array} modules Either the name of a module, array of modules, * or a URL of an external script or style * @param {string} [type='text/javascript'] MIME type to use if calling with a URL of an @@ -2048,25 +2080,21 @@ modules = [ modules ]; } - // Filter out undefined modules, otherwise resolve() will throw - // an exception for trying to load an undefined module. - // Undefined modules are acceptable here in load(), because load() takes - // an array of unrelated modules, whereas the modules passed to - // using() are related and must all be loaded. + // Filter out top-level modules that are unknown or failed to load before. filtered = $.grep( modules, function ( module ) { var state = mw.loader.getState( module ); - return state !== null && state !== 'error' && state !== 'missing'; + return state !== 'error' && state !== 'missing'; } ); - - if ( filtered.length === 0 ) { - return; - } - // Resolve entire dependency map - filtered = resolve( filtered ); + // Resolve remaining list using the known dependency tree. + // This also filters out modules with unknown dependencies. (T36853) + filtered = resolveStubbornly( filtered ); // If all modules are ready, or if any modules have errors, nothing to be done. if ( allReady( filtered ) || anyFailed( filtered ) ) { return; } + if ( filtered.length === 0 ) { + return; + } // Some modules are not yet ready, add to module load queue. enqueue( filtered, undefined, undefined ); }, @@ -2754,14 +2782,16 @@ * @member mw.hook */ $( function () { - var loading = $.grep( mw.loader.getModuleNames(), function ( module ) { + var loading, modules; + + modules = $.grep( mw.loader.getModuleNames(), function ( module ) { return mw.loader.getState( module ) === 'loading'; } ); // We only need a callback, not any actual module. First try a single using() // for all loading modules. If one fails, fall back to tracking each module // separately via $.when(), this is expensive. - loading = mw.loader.using( loading ).then( null, function () { - var all = loading.map( function ( module ) { + loading = mw.loader.using( modules ).then( null, function () { + var all = modules.map( function ( module ) { return mw.loader.using( module ).then( null, function () { return $.Deferred().resolve(); } );