2012-01-03 18:33:26 +00:00
|
|
|
<?php
|
2012-02-09 09:34:47 +00:00
|
|
|
/**
|
2012-04-28 18:41:55 +00:00
|
|
|
* Implements Special:JavaScriptTest
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
|
* http://www.gnu.org/copyleft/gpl.html
|
|
|
|
|
*
|
2012-02-09 09:34:47 +00:00
|
|
|
* @file
|
2012-04-28 18:41:55 +00:00
|
|
|
* @ingroup SpecialPage
|
2012-02-09 09:34:47 +00:00
|
|
|
*/
|
2012-01-03 18:33:26 +00:00
|
|
|
|
2012-02-09 09:34:47 +00:00
|
|
|
/**
|
|
|
|
|
* @ingroup SpecialPage
|
|
|
|
|
*/
|
2012-01-03 18:33:26 +00:00
|
|
|
class SpecialJavaScriptTest extends SpecialPage {
|
|
|
|
|
|
|
|
|
|
public function __construct() {
|
|
|
|
|
parent::__construct( 'JavaScriptTest' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function execute( $par ) {
|
2019-10-27 22:10:02 +00:00
|
|
|
$this->getOutput()->disable();
|
2014-12-02 21:48:21 +00:00
|
|
|
|
2016-03-31 20:18:14 +00:00
|
|
|
if ( $par === 'qunit/export' ) {
|
2019-10-27 22:10:02 +00:00
|
|
|
// Send the JavaScript payload.
|
|
|
|
|
$this->exportJS();
|
|
|
|
|
} elseif ( $par === null || $par === '' || $par === 'qunit' || $par === 'qunit/plain' ) {
|
|
|
|
|
// Render the page
|
|
|
|
|
// (Support "/qunit" and "/qunit/plain" for backwards-compatibility)
|
|
|
|
|
$this->renderPage();
|
|
|
|
|
} else {
|
|
|
|
|
wfHttpError( 404, 'Unknown action', "Unknown action \"$par\"." );
|
2012-01-03 18:33:26 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-10-27 22:10:02 +00:00
|
|
|
* Send the standalone JavaScript payload.
|
2014-12-02 21:48:21 +00:00
|
|
|
*
|
2022-01-09 17:58:53 +00:00
|
|
|
* Loaded by the GUI (on Special:JavaScriptTest), and by the CLI (via grunt-karma).
|
2014-12-02 21:48:21 +00:00
|
|
|
*/
|
2019-10-27 22:10:02 +00:00
|
|
|
private function exportJS() {
|
2014-12-02 21:48:21 +00:00
|
|
|
$out = $this->getOutput();
|
|
|
|
|
$rl = $out->getResourceLoader();
|
|
|
|
|
|
2020-02-22 01:01:24 +00:00
|
|
|
// Allow framing (disabling wgBreakFrames). Otherwise, mediawiki.page.ready
|
|
|
|
|
// will close this tab when running from CLI using karma-qunit.
|
2021-09-29 20:58:59 +00:00
|
|
|
$out->setPreventClickjacking( false );
|
2019-10-27 22:10:02 +00:00
|
|
|
|
2016-02-17 09:09:32 +00:00
|
|
|
$query = [
|
2019-10-27 22:25:50 +00:00
|
|
|
'lang' => 'qqx',
|
|
|
|
|
'skin' => 'fallback',
|
2021-12-06 13:33:28 +00:00
|
|
|
'debug' => (string)ResourceLoader::inDebugMode(),
|
2015-06-04 20:12:23 +00:00
|
|
|
'target' => 'test',
|
2016-02-17 09:09:32 +00:00
|
|
|
];
|
2014-12-02 21:48:21 +00:00
|
|
|
$embedContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) );
|
|
|
|
|
$query['only'] = 'scripts';
|
|
|
|
|
$startupContext = new ResourceLoaderContext( $rl, new FauxRequest( $query ) );
|
|
|
|
|
|
2019-07-30 15:06:35 +00:00
|
|
|
$modules = $rl->getTestSuiteModuleNames();
|
2022-02-02 10:00:12 +00:00
|
|
|
$component = $this->getContext()->getRequest()->getVal( 'component' );
|
|
|
|
|
if ( $component ) {
|
|
|
|
|
$module = 'test.' . $component;
|
|
|
|
|
if ( !in_array( 'test.' . $component, $modules ) ) {
|
|
|
|
|
wfHttpError(
|
|
|
|
|
404,
|
|
|
|
|
'Unknown test module',
|
|
|
|
|
"'$module' is not a defined test module. "
|
|
|
|
|
. 'Register one via the QUnitTestModules attribute in extension.json.'
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$modules = [ 'test.' . $component ];
|
|
|
|
|
}
|
2014-12-02 21:48:21 +00:00
|
|
|
|
qunit: Disable mw.loader.store server-side instead of client-side
== What
This feature is disabled initially because we want to be able to
test it. When mw.loader's own tests are testing mw.loader.store,
they are mocking setTimeout and mw.requestIdleCallback, so that
they can then make mw.loader.store schedule its "flush" callback
and via the mock timer control when it executes and then assert
its result.
== The Bad
Previously an inline JS hack was concatenated right after startup.js,
and that seems like it should be early enough to prevent anything
from initialising mw.loader.store and scheduling a real 2s flush timer.
There is no obvious sign here that the startup module response would
request or implement a module (which could inititialise mw.loader.store).
However, there is.
== …, the Ugly
The startup response contains RLQ processing (which is empty in
the standalone test runner, so no worries here) and a call to
mw.loader.load for RLPAGEMODULES. The RLPAGEMODULES list is empty,
but it does still make a call to mw.loader.load(). And that
expands the empty array to include jquery+mediawiki.base and thus
makes a proper module request, which then initialises mw.loader.store
and schedules its 2s flush timeout.
This hasn't caused failing tests in CI so far, because there are
generally at least 2 seconds of unrelated tests that run first.
So by the time mw.loader's test suite comes around, it has
been disabled and the previous flush has already completed.
== … and the Good
Change I5f1067feb0a43d makes the 'mediawiki.jqueryMsg' test suite
super fast (previously took 2+ seconds, longer than any other test).
This exposes the fact that mw.loader.store was in fact not
actually properly disabled from the get go, and so tests would
be failing.
Bug: T250045
Change-Id: I38c3ad2a9a5813215dbb210bddafcc3cdd70295d
2020-04-22 23:54:20 +00:00
|
|
|
// Disable module storage.
|
|
|
|
|
// The unit test for mw.loader.store will enable it (with a mock timers).
|
|
|
|
|
$config = new MultiConfig( [
|
|
|
|
|
new HashConfig( [ 'ResourceLoaderStorageEnabled' => false ] ),
|
|
|
|
|
$rl->getConfig(),
|
|
|
|
|
] );
|
|
|
|
|
|
2015-07-28 02:46:00 +00:00
|
|
|
// Disable autostart because we load modules asynchronously. By default, QUnit would start
|
|
|
|
|
// at domready when there are no tests loaded and also fire 'QUnit.done' which then instructs
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
// Karma to exit the browser process before the tests even finished loading.
|
2015-07-28 02:46:00 +00:00
|
|
|
$qunitConfig = 'QUnit.config.autostart = false;'
|
|
|
|
|
. 'if (window.__karma__) {'
|
|
|
|
|
// karma-qunit's use of autostart=false and QUnit.start conflicts with ours.
|
2019-08-20 00:47:01 +00:00
|
|
|
// Hack around this by replacing 'karma.loaded' with a no-op and perform its duty of calling
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
// `__karma__.start()` ourselves. See <https://github.com/karma-runner/karma-qunit/issues/27>.
|
2015-07-28 02:46:00 +00:00
|
|
|
. 'window.__karma__.loaded = function () {};'
|
|
|
|
|
. '}';
|
|
|
|
|
|
resourceloader: Move queue formatting out of OutputPage
HTML formatting of the queue was distributed over several OutputPage methods.
Each method demanding a snippet of HTML by calling makeResourceLoaderLink()
with a limited amount of information. As such, makeResourceLoaderLink() was
unable to provide the client with the proper state information.
Centralising it also allows it to better reduce duplication in HTML output
and maintain a more accurate state.
Problems fixed by centralising:
1. The 'user' module is special (due to per-user 'version' and 'user' params).
It is manually requested via script-src. To avoid a separate (and wrong)
request from something that requires it, we set state=loading directly.
However, because the module is in the bottom, the old HTML formatter could
only put state=loading in the bottom also. This sometimes caused a wrong
request to be fired for modules=user if something in the top queue
triggered a requirement for it.
2. Since a464d1d4 (T87871) we track states of page-style modules, with purpose
of allowing dependencies on style modules without risking duplicate loading
on pages where the styles are loaded already. This didn't work, because the
state information about page-style modules is output near the stylesheet,
which is after the script tag with mw.loader.load(). That runs first, and
mw.loader would still make a duplicate request before it learns the state.
Changes:
* Document reasons for style/script tag order in getHeadHtml (per 09537e83).
* Pass $type from getModuleStyles() to getAllowedModules(). This wasn't needed
before since a duplicate check in makeResourceLoaderLink() verified the
origin a second time.
* Declare explicit position 'top' on 'user.options' and 'user.tokens' module.
Previously, OutputPage hardcoded them in the top. The new formatter doesn't.
* Remove getHeadScripts().
* Remove getInlineHeadScripts().
* Remove getExternalHeadScripts().
* Remove buildCssLinks().
* Remove getScriptsForBottomQueue().
* Change where Skin::setupSkinUserCss() is called. This methods lets the skin
add modules to the queue. Previously it was called from buildCssLinks(),
via headElement(), via prepareQuickTemplate(), via OutputPage::output().
It's now in OutputPage::output() directly (slightly earlier). This is needed
because prepareQuickTemplate() calls bottomScripts() before headElement().
And bottomScript() would lazy-initialise the queue and lock it before
setupSkinUserCss() is called from headElement().
This makes execution order more predictable instead of being dependent on
the arbitrary order of data extraction in prepareQuickTemplate (which varies
from one skin to another).
* Compute isUserModulePreview() and isKnownEmpty() for the 'user' module early
on so. This avoids wrongful loading and fixes problem 1.
Effective changes in output:
* mw.loader.state() is now before mw.loader.load(). This fixes problem 2.
* mw.loader.state() now sets 'user.options' and 'user.tokens' to "loading".
* mw.loader.state() now sets 'user' (as "loading" or "ready"). Fixes problem 1.
* The <script async src> tag for 'startup' changed position (slightly).
Previously it was after all inline scripts and stylesheets. It's still after
all inline scripts and after most stylesheets, but before any user styles.
Since the queue is now formatted outside OutputPage, it can't inject the
meta-ResourceLoaderDynamicStyles tag and user-stylesheet hack in the middle
of existing output. This shouldn't have any noticable impact.
Bug: T87871
Change-Id: I605b8cd1e1fc009b4662a0edbc54d09dd65ee1df
2016-07-15 14:13:09 +00:00
|
|
|
// The below is essentially a pure-javascript version of OutputPage::headElement().
|
qunit: Disable mw.loader.store server-side instead of client-side
== What
This feature is disabled initially because we want to be able to
test it. When mw.loader's own tests are testing mw.loader.store,
they are mocking setTimeout and mw.requestIdleCallback, so that
they can then make mw.loader.store schedule its "flush" callback
and via the mock timer control when it executes and then assert
its result.
== The Bad
Previously an inline JS hack was concatenated right after startup.js,
and that seems like it should be early enough to prevent anything
from initialising mw.loader.store and scheduling a real 2s flush timer.
There is no obvious sign here that the startup module response would
request or implement a module (which could inititialise mw.loader.store).
However, there is.
== …, the Ugly
The startup response contains RLQ processing (which is empty in
the standalone test runner, so no worries here) and a call to
mw.loader.load for RLPAGEMODULES. The RLPAGEMODULES list is empty,
but it does still make a call to mw.loader.load(). And that
expands the empty array to include jquery+mediawiki.base and thus
makes a proper module request, which then initialises mw.loader.store
and schedules its 2s flush timeout.
This hasn't caused failing tests in CI so far, because there are
generally at least 2 seconds of unrelated tests that run first.
So by the time mw.loader's test suite comes around, it has
been disabled and the previous flush has already completed.
== … and the Good
Change I5f1067feb0a43d makes the 'mediawiki.jqueryMsg' test suite
super fast (previously took 2+ seconds, longer than any other test).
This exposes the fact that mw.loader.store was in fact not
actually properly disabled from the get go, and so tests would
be failing.
Bug: T250045
Change-Id: I38c3ad2a9a5813215dbb210bddafcc3cdd70295d
2020-04-22 23:54:20 +00:00
|
|
|
$startupModule = $rl->getModule( 'startup' );
|
|
|
|
|
$startupModule->setConfig( $config );
|
|
|
|
|
$code = $rl->makeModuleResponse( $startupContext, [ 'startup' => $startupModule ] );
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
// The following has to be deferred via RLQ because the startup module is asynchronous.
|
|
|
|
|
$code .= ResourceLoader::makeLoaderConditionalScript(
|
|
|
|
|
// Embed page-specific mw.config variables.
|
2019-04-02 19:51:35 +00:00
|
|
|
//
|
|
|
|
|
// For compatibility with older tests, these will come from the user
|
|
|
|
|
// action "viewing Special:JavaScripTest".
|
|
|
|
|
//
|
|
|
|
|
// This is deprecated since MediaWiki 1.25 and slowly being phased out in favour of:
|
|
|
|
|
// 1. tests explicitly mocking the configuration they depend on.
|
|
|
|
|
// 2. tests explicitly skipping or not loading code that is only meant
|
|
|
|
|
// for real page views (e.g. not loading as dependency, or using a QUnit
|
|
|
|
|
// conditional).
|
|
|
|
|
ResourceLoader::makeConfigSetScript( array_intersect_key(
|
|
|
|
|
$out->getJSVars(),
|
|
|
|
|
// Keep a select few that are commonly referenced.
|
|
|
|
|
// See https://phabricator.wikimedia.org/T89434.
|
|
|
|
|
array_fill_keys(
|
|
|
|
|
[
|
|
|
|
|
'wgPageName', // used by mediawiki.util
|
|
|
|
|
'wgRelevantPageName', // used as input for mw.Title
|
|
|
|
|
],
|
|
|
|
|
null
|
|
|
|
|
)
|
|
|
|
|
) )
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
// Embed private modules as they're not allowed to be loaded dynamically
|
|
|
|
|
. $rl->makeModuleResponse( $embedContext, [
|
|
|
|
|
'user.options' => $rl->getModule( 'user.options' ),
|
|
|
|
|
] )
|
|
|
|
|
// Load all the test suites
|
|
|
|
|
. Xml::encodeJsCall( 'mw.loader.load', [ $modules ] )
|
|
|
|
|
);
|
|
|
|
|
$encModules = Xml::encodeJsVar( $modules );
|
|
|
|
|
$code .= ResourceLoader::makeInlineCodeWithModule( 'mediawiki.base', <<<JAVASCRIPT
|
2017-04-27 18:05:25 +00:00
|
|
|
var start = window.__karma__ ? window.__karma__.start : QUnit.start;
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
mw.loader.using( $encModules ).always( start );
|
|
|
|
|
mw.trackSubscribe( 'resourceloader.exception', function ( topic, err ) {
|
|
|
|
|
// Things like "dependency missing" or "unknown module".
|
|
|
|
|
// Re-throw so that they are reported as global exceptions by QUnit and Karma.
|
|
|
|
|
setTimeout( function () {
|
2018-08-16 06:28:17 +00:00
|
|
|
throw err;
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
} );
|
|
|
|
|
} );
|
|
|
|
|
JAVASCRIPT
|
|
|
|
|
);
|
2014-12-02 21:48:21 +00:00
|
|
|
|
|
|
|
|
header( 'Content-Type: text/javascript; charset=utf-8' );
|
|
|
|
|
header( 'Cache-Control: private, no-cache, must-revalidate' );
|
|
|
|
|
header( 'Pragma: no-cache' );
|
2015-07-28 02:46:00 +00:00
|
|
|
echo $qunitConfig;
|
resourceloader: Combine base modules and page modules requests
This commit implements step 4 and step 5 of the plan outlined at T192623.
Before this task began, the typical JavaScript execution flow was:
* HTML triggers request for startup module (js req 1).
* Startup module contains registry, site config, and triggers
a request for the base modules (js req 2).
* After the base modules arrive (which define jQuery and mw.loader),
the startup module invokes a callback that processes RLQ,
which is what will request modules for this page (js req 3).
In past weeks, we have:
* Made mediawiki.js independent of jQuery.
* Spun off 'mediawiki.base' from mediawiki.js – for everything
that wasn't needed for defining `mw.loader`.
* Moved mediawiki.js from the base module request to being embedded
as part of startup.js.
The concept of dependencies is native to ResourceLoader, and thanks to the
use of closures in mw.loader.implement() responses, we can download any
number of interdependant modules in a single request (or parallel requests).
Then, when a response arrives, mw.loader takes care to pause or resume
execution as-needed. It is normal for ResourceLoader to batch several modules
together, including their dependencies.
As such, we can eliminate one of the two roundtrips required before a
page can request modules. Specifically, we can eliminate "js req 2" (above),
by making the two remaining base modules ("jquery" and "mediawiki.base") an
implied dependency for all other modules, which ResourceLoader will naturally
fetch and execute in the right order as part of the batch request.
Bug: T192623
Change-Id: I17cd13dffebd6ae476044d8d038dc3974a1fa176
2018-07-12 20:09:28 +00:00
|
|
|
echo $code;
|
2014-12-02 21:48:21 +00:00
|
|
|
}
|
|
|
|
|
|
2019-10-27 22:10:02 +00:00
|
|
|
private function renderPage() {
|
2019-10-27 21:57:48 +00:00
|
|
|
$basePath = $this->getConfig()->get( 'ResourceBasePath' );
|
2019-10-27 22:10:02 +00:00
|
|
|
$headHtml = implode( "\n", [
|
2019-10-27 21:57:48 +00:00
|
|
|
Html::linkedScript( "$basePath/resources/lib/qunitjs/qunit.js" ),
|
|
|
|
|
Html::linkedStyle( "$basePath/resources/lib/qunitjs/qunit.css" ),
|
|
|
|
|
Html::linkedStyle( "$basePath/resources/src/qunitjs/qunit-local.css" ),
|
|
|
|
|
] );
|
2015-07-28 02:46:00 +00:00
|
|
|
|
2019-10-27 22:10:02 +00:00
|
|
|
$introHtml = $this->msg( 'javascripttest-qunit-intro' )
|
|
|
|
|
->params( 'https://www.mediawiki.org/wiki/Manual:JavaScript_unit_testing' )
|
|
|
|
|
->parseAsBlock();
|
|
|
|
|
|
|
|
|
|
$scriptUrl = $this->getPageTitle( 'qunit/export' )->getFullURL( [
|
2021-12-06 13:33:28 +00:00
|
|
|
'debug' => (string)ResourceLoader::inDebugMode(),
|
2016-02-17 09:09:32 +00:00
|
|
|
] );
|
2019-10-27 22:10:02 +00:00
|
|
|
$script = Html::linkedScript( $scriptUrl );
|
2014-12-02 21:48:21 +00:00
|
|
|
|
|
|
|
|
header( 'Content-Type: text/html; charset=utf-8' );
|
2019-10-27 22:10:02 +00:00
|
|
|
echo <<<HTML
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<title>QUnit</title>
|
|
|
|
|
$headHtml
|
|
|
|
|
$introHtml
|
|
|
|
|
<div id="qunit"></div>
|
|
|
|
|
$script
|
|
|
|
|
HTML;
|
2012-01-03 18:33:26 +00:00
|
|
|
}
|
2013-03-07 20:15:54 +00:00
|
|
|
|
|
|
|
|
protected function getGroupName() {
|
|
|
|
|
return 'other';
|
|
|
|
|
}
|
2012-01-03 18:33:26 +00:00
|
|
|
}
|