Part 1, proof of concept. Hundreds of files left to go. These changes
brought to you in large part by vim macros.
Bug: T305805
Change-Id: I44789091e9f6394c800a11b29f22528c8dcacf71
On special pages where disallowUserJs() is used, or when setting
safemode=1 by hand to index.php, disable mw.loader.store.
OutputPage already normalizes disallowUserJs() to safemode=1 as
passed on to ResourceLoaderClientHtml and ResourceLoaderContext.
Use it in the startup mode to disable this feature.
Invert the internal substitution variable to avoid confusing
double negatives, and to match the config name.
Bug: T145498
Change-Id: I2fdba968b4703ec8826bdaf91340bdead058f02b
Make phan stricter about conditional variable declaration
Remaining false positive issues are suppressed.
The suppression and the setting change can only be done together
Bug: T259172
Change-Id: I1f200ac37df7448453688bf464a8250c97313e5d
Make phan stricter about array keys
Remaining false positive issues are suppressed.
The suppression and the setting change can only be done together
Bug: T304887
Depends-On: I3105a5fd4826f8667b5232834defc5ec93be32a1
Depends-On: Ie9610a6e83731468311edb3ed17f80fc509de385
Change-Id: I701f12ab94478c3b8e7fd82110ade74a8e6b04ef
Logo variant override is available for 'wordmark' and 'tagline' in
the new Vector skin and has been used for a while, but the 'logo'
feature built in the core didn't take variants into account.
The logic should be pushed down to ResourceLoaderSkinModule so that
behavior can be consistent between skins and core.
Also, old code use $title->getPageViewLanguage() to determine the
variant of logo, which is a wrong behavior. Logos should be in the
interface language instead of the content variant.
Bug: T273578
Change-Id: Ifb3cc45600d57cf9c72757016148684cd7ab1400
Registering fewer modules reduces the size of the startup module.
The current skin is read from the skin parameter to the load.php
request. Modules can opt-in by specifying skins in which they are
relevant, by overriding getSkins() of ResourceLoaderModule.
Bug: T253582
Bug: T236603
Change-Id: I08a1a59b4eab90d380ca8f874bb6dbba2f399590
Conventionally, public constants are accessed via their declaring
class, except for self:: which is an acceptable shortcut.
Change-Id: If05eab72140267e6ef54736710d751d7f24a7860
There are now 4 types of logos, only one of which is needed.
Update documentation in installer to reflect this.
Also make it possible to drag and drop files into the installer
and see live previews of what the logos will look like to aid
setup.
The 1x is no longer required.
Bug: T255913
Change-Id: I58226ae8fb02c32d2eeea65a50aaabbc193cb51c
* Explain the optimisation in this method.
* Improve overall docs.
* Bring the getTitleInfo() fetch closer to where it is needed,
which is also a micro optimisation in itself by not fetching
in case of the early return (though that's a rare case).
Bug: T299288
Change-Id: I104cf20ab5a944ec382c5807e8bf1bf18979d426
This adds support for the `exports` alias for `module.exports`, but only
to package modules, per the discussion on T284511. This makes it easier
to use external libraries that use UMD, since UMD tests whether
typeof exports === "object", and if not, it adds the library to the
global scope instead of exporting it.
This is a breaking change for package modules that were expecting
exports to be undefined; in practice, this means modules that were
expecting UMD wrappers to add to the global scope have to be updated to
expect it to export the library instead. However, most UMD wrappers in
MW core are in non-package files, which are not affected by this change.
The affected libraries are updated accordingly:
- Codex used the global scope. This library is very new and nothing uses
the global window.codex variable yet, so we don't need to provide
backwards compatibility for it.
- Pako was patched to have its UMD wrapper look at module instead of
exports; remove this patch since it's now unnecessary
Bug: T284511
Change-Id: Ie2e965cee001fb7f10b2b3e3f796d9511f6b63d2
Helps reduce the size of the user.options module by not adding options that are
unlikely to be of use in JavaScript.
Bug: T251994
Change-Id: I7701d094a3e905edeab7571dca34db5b20a13d68
Don't catch and discard exceptions from the RequestTimeout library,
except when the exception is properly handled and the code seems to be
trying to wrap things up.
In most cases the exception is rethrown. Ideally it should instead be
done by narrowing the catch, and this was feasible in a few cases. But
sometimes the exception being caught is an instance of the base class
(notably DateTime::__construct()). Often Exception is the root of the
hierarchy of exceptions being thrown and so is the obvious catch-all.
Notes on specific callers:
* In the case of ResourceLoader::respond(), exceptions were caught for API
correctness, but processing continued. I added an outer try block for
timeout handling so that termination would be more prompt.
* In LCStoreCDB the Exception being caught was Cdb\Exception not
\Exception. I added an alias to avoid confusion.
* In ImageGallery I added a special exception class.
* In Message::__toString() the rationale for catching disappears
in PHP 7.4.0+, so I added a PHP version check.
* In PoolCounterRedis, let the shutdown function do its thing, but
rethrow the exception for logging.
Change-Id: I4c3770b9efc76a1ce42ed9f59329c36de04d657c
This change exposes the requiresES6 flag to the public API,
specifically via getState() by not registering modules that
aren't available / can't be loaded in the context.
This actually simplifies the code a fair bit, and partially reverts
the added logic from I45670c910ff12.
Bug: T299677
Change-Id: I96a03796628a74ace93579d45a582711400c09c1
If a skin e.g. Minerva is using an opt-in policy then it has already
decided what features to load. It should not be subjected to features
it hasn't requested.
This was leading to content-external-links being loaded in Minerva
since 8c1afd97a3.
Bug: T298433
Change-Id: I621621bc2d30ee9ce00decbdee0f55c4db65abc1
* Enforce the ban on is_resource in phpcs
* In OrderedStreamingForkController, the comment was incorrect. I
confirmed using a small test script that if the child closes one end
of a socket pair, the other end will still be open, and is_resource()
will still return true, and fclose() will not fail. The issue was
introduced in c82d30d19c, it was not present in the
CirrusSearch copy of the class.
* Allow is_resource() for debug logging.
* Allow is_resource() for parameter validation where a stream may be
passed to a function, since there is no alternative.
Bug: T260735
Change-Id: I59a752f7bb4b043ddfb2434b52a02f9221bf54db
== What ==
Change debug mode 2 to behave more like production mode:
* use module scope (no longer global scope).
* load modules concurrently (no longer each module serially).
* bundle files (no longer each file separately).
What remains different in debug=2 from production mode:
* disable minification.
* disable batching (one module per request).
== How ==
* Limit the old logic (getScriptURLsForDebug) to just legacy debug.
* Set maxQueryLength=0 for non-legacy debug, to ensure each module
still gets its own dedicated request for easy debugging, and to
get concurrency to make more optimal use of server and browser
capacity.
This does not effect package file modules much, as those already
worked in this way. The only difference for package file modules
is that they now load faster (see below) by eliminating the
in-between request.
== Alternative approach ==
An alternative approach, which I considered, is to modify
Module::buildContent(), around where we currently call
getScriptURLsForDebug for DEBUG_LEGACY, and add a conditional branch
for DEBUG_MAIN which would always return an array with a single URL,
to `load.php?modules=:name`. Much like getScriptURLsForDebug does by
default, but without the legacy-specific overrides to that method from
e.g. FileModule.
I decided against this because the mw.loader client handles such
script-arrays in a global FIFO fashion, tailored for legacy debug mode
where it crucial to only serially queue>load>execute one script file
of one module at any given time (because the raw files can't have a
"mw.loader.implement" closure and thus execute immediately on arrival,
with no other coordination for file order and module dependency order).
This would make debug=2 slow, possibly slower than debug=1 since in
debug=1 at least we consolidate most PHP roundtrips in a single batch,
and most other scripts can be served quickly as static file by Apache.
By letting the client act like it does for production mode, and
proactively split its requests, we get a few benefits compared to
this alternative approach:
* Fewer requests and shorter request dependency chain.
There is no in-between request for the "page module batch" that fans
out to individual module reqs. Instead, the client makes those reqs
directly.
* All module requests are discovered and queued with the browser in
one go, letting the server handle them as quickly as it can.
In production, probably all in parallel. Locally, mediawiki-docker
seems to handle about 6 at time (this depite having 10 php-fpm
proccess). I suspect that maybe due to a poor interactions between
HTTP1 connection reuse and keep-alive timeouts, or perhaps unneeded
session locks with sqlite.
* The browser can spend time parsing/compiling other requests at the
same time as one of them executes.
* No additional client-side logic.
* No increase in client payload.
Bug: T85805
Change-Id: I232310eb624e0204484ec9f3d715d5b6b8532fe8
* Use the int result of `ResourceLoader::inDebugMode()` directly in
SpecialJavaScriptTest so that debug=2 is passed on to the next
request, like it does on regular page views.
This is likely temporary, because
part of T85805 is to make debug=true default to debug=2, and
part of T250045 is to hardcode debug=2 for JavaScriptTest.
* Add a few line breaks to improve HTML output readability in debug
mode. This is a no-op for prod as they get minified away.
Today I learned: PHP string heredoc and nowdoc syntax strip not
only the shared common indentation (which I knew), it also strips
the first and last newline. Hence, switching ClientHtml to use
double quotes.
* Document the order in which lang/skin/debugScripts execute.
Bug: T85805
Bug: T250045
Change-Id: I2ad179401cee6cf6ba30c0b462f0d48a8529ba74
The docs for wgResourceLoaderMaxage still described the "server"
and "client" subkeys, which have not existed since MW 1.35. This
was essentially a new configuration structure, add the `@since`
annotation to reflect this.
Clean up the ResourceLoader class and group together related class
members in a more logical way. Currently going for what I see various
other core components do:
* Constants: public, then private.
* Static: public, then private.
* Members: public (none), then ctor-assigned/injected stuff, then
those with defaults that start as-is.
Make most protected members private, except for those intentionally
made protected for use in tests. This class is not meant to be
extended, is not marked as stable for that purpose, and Codesearch
shows no extensions that do so.
Remove unused internal '$testModuleNames' field. This was removed in
5f47d994bc and accidentally reintroduced (unused) with 440dfcf6d8,
presumably due to a bad rebase.
Bug: T32956
Change-Id: I041a320d05c9e5f30ac9cc9270ce82c4d19a957f
Packaged modules don't support URL-loading. It leads to two mw.loader.implement() calls with the same module name, giving an exception.
A similar override of supportsURLLoading() is already being done in ResourceLoaderFileModule.
Bug: T198758
Change-Id: Id4589a597ccfc4266b3e63d10f75b146aa7a287a
We upgraded to version 2.2.6 of wikimedia/minify a few weeks ago, but
broken minifications from that version have lingered in the minification
cache. Bump the cache version to fix this.
Bug: T296058
Follows-Up: I6bceffda0c7ff4f4d92e15e85ae8719426ff4c3f
Change-Id: I7560c8ae54f3132cb33e8823dbfb467fef0cfc31
* Magnify clip isn't present in print styling
* Print and screen thumbborder are different
* Print thumbinner and thumbimage borders are absent
Bug: T287965
Change-Id: Ie1dac57412da7da3e73eb39ef20a6077923860d6
* Upgrade Vue to @vue/compat version 3.2.23
* Migrate Vue.createMwApp to Vue 3 API
* Add backwards-compatible wrapper emulating Vue 2 behavior for
new Vue( { el: '#foo', ... } ) and
new Vue( ... ).$mount( '#foo' )
* Make @vue/composition-api an alias for vue, for b/c
* Convert resources/src/vue/ to ES6
* Ignore resource/src/vue/ for jsduck, since it doesn't support ES6
* VueComponentParser: Remove check for only one root node
Bug: T251974
Co-Authored-By: Lucas Werkmeister <lucas.werkmeister@wikimedia.de>
Depends-On: Ica0c0d0d6247383796d39199e50a9aff917f5b53
Change-Id: Ibd618765f962f57984994604c61b1aff9e6a778d
Follow up to I076fddda07dd734f76277376ba6361bff68b7c36
Also, adds a comment about -legacy being frozen.
Change-Id: Iced54fb31c967975248bfc9908d904fa41824307
This allows the backend to do whatever it can to ensure atomicity, and
is also easier to read, since the intent is obvious.
Change-Id: Ibbfecd92a2c6d9a5997ca37ea101e068bd1e8202
== Background ==
The `user.options` module is private, and thus has to be embedded in
the page HTML. This data is quite large. For example, on enwiki the
finalized mw.user.options object is about 3KB serialized/compressed
(7KB uncompressed).
The `user.defaults` module is an implementation detail of
`user.options`, and was created to accomplish mainly two things:
* Save significant data transfers by allowing it to be cached
client-side without being part of the article.
* Ensure consistency between articles and allow faster deployment of
changes, by not being part of the cacheable article HTML.
All our pageviews already load `user.defaults`, as a dependency of
the popular `mediawiki.api` and `mediawiki.user` modules. These are
used by `mediawiki.page.ready` (queued on all pages), and on Wikipedia
these are also loaded on all pages by ULS, VisualEditor, EventLogging,
and more.
As such, in practice, bundling "user.defaults" with "mediawiki.base"
will not cause the data to be loaded more often than before.
== What ==
* Add virtual "user.json" package file with the same data that
was previously exported by ResourceLoaderUserDefaultsModule,
and pass it to mw.user.options.set() from base module's entry point.
An alternative way would be to use a "user.js" file, which would
return a generated "mw.user.options.set()" expression. I went
for exporting it as JSON for improved maintainability (reducing
the amount of JS code written in PHP), and because it performs
slightly better. The JS file would implicitly come with a file
closure (tiny bit more bytes), and would then be lazy executed
(tiny bit more time).
The chosen approach allows the browser to compile the JSON
off-the-main-thread ahead of time while the module response downloads.
Then when the module executes, we can reference the JSON object
and use it directly.
* Update internal dependency from `user.options`.
* Remove `user.defaults` module without deprecation. It is an internal
module with no direct use anywhere in Git (Codeseach), and no use
anywhere on-wiki (Global Search).
Change-Id: Id3916f94f75078808951863dea2b3a9c71b0e30c