foreach ( $modules as $name => $module ) {
try {
$content = $module->getModuleContent( $context );
+ $implementKey = $name . '@' . $module->getVersionHash( $context );
$strContent = '';
// Append output
$strContent = $scripts;
} elseif ( is_array( $scripts ) ) {
// ...except when $scripts is an array of URLs
- $strContent = self::makeLoaderImplementScript( $name, $scripts, [], [], [] );
+ $strContent = self::makeLoaderImplementScript( $implementKey, $scripts, [], [], [] );
}
break;
case 'styles':
$strContent = isset( $styles['css'] ) ? implode( '', $styles['css'] ) : '';
break;
default:
+ $scripts = isset( $content['scripts'] ) ? $content['scripts'] : '';
+ if ( is_string( $scripts ) ) {
+ if ( $name === 'site' || $name === 'user' ) {
+ // Legacy scripts that run in the global scope without a closure.
+ // mw.loader.implement will use globalEval if scripts is a string.
+ // Minify manually here, because general response minification is
+ // not effective due it being a string literal, not a function.
+ if ( !ResourceLoader::inDebugMode() ) {
+ $scripts = self::filter( 'minify-js', $scripts ); // T107377
+ }
+ } else {
+ $scripts = new XmlJsCode( $scripts );
+ }
+ }
$strContent = self::makeLoaderImplementScript(
- $name,
- isset( $content['scripts'] ) ? $content['scripts'] : '',
+ $implementKey,
+ $scripts,
isset( $content['styles'] ) ? $content['styles'] : [],
isset( $content['messagesBlob'] ) ? new XmlJsCode( $content['messagesBlob'] ) : [],
isset( $content['templates'] ) ? $content['templates'] : []
/**
* Return JS code that calls mw.loader.implement with given module properties.
*
- * @param string $name Module name
- * @param mixed $scripts List of URLs to JavaScript files or String of JavaScript code
+ * @param string $name Module name or implement key (format "`[name]@[version]`")
+ * @param XmlJsCode|array|string $scripts Code as XmlJsCode (to be wrapped in a closure),
+ * list of URLs to JavaScript files, or a string of JavaScript for `$.globalEval`.
* @param mixed $styles Array of CSS strings keyed by media type, or an array of lists of URLs
* to CSS files keyed by media type
* @param mixed $messages List of messages associated with this module. May either be an
* @throws MWException
* @return string
*/
- public static function makeLoaderImplementScript(
+ protected static function makeLoaderImplementScript(
$name, $scripts, $styles, $messages, $templates
) {
- if ( is_string( $scripts ) ) {
- // Site and user module are a legacy scripts that run in the global scope (no closure).
- // Transportation as string instructs mw.loader.implement to use globalEval.
- if ( $name === 'site' || $name === 'user' ) {
- // Minify manually because the general makeModuleResponse() minification won't be
- // effective here due to the script being a string instead of a function. (T107377)
- if ( !ResourceLoader::inDebugMode() ) {
- $scripts = self::filter( 'minify-js', $scripts );
- }
- } else {
- $scripts = new XmlJsCode( "function ( $, jQuery, require, module ) {\n{$scripts}\n}" );
- }
- } elseif ( !is_array( $scripts ) ) {
+
+ if ( $scripts instanceof XmlJsCode ) {
+ $scripts = new XmlJsCode( "function ( $, jQuery, require, module ) {\n{$scripts->value}\n}" );
+ } elseif ( !is_string( $scripts ) && !is_array( $scripts ) ) {
throw new MWException( 'Invalid scripts error. Array of URLs or string of code expected.' );
}
// mw.loader.implement requires 'styles', 'messages' and 'templates' to be objects (not
* Values considered empty:
*
* - null
- * - array()
+ * - []
* - new XmlJsCode( '{}' )
- * - new stdClass() // (object) array()
+ * - new stdClass() // (object) []
*
* @param Array $array
*/