Commit graph

128 commits

Author SHA1 Message Date
Timo Tijhof
2581453fac resourceloader: Enable module content version for data modules
This greatly simplifies logic required to compute module versions.
It also makes it significantly less error-prone.

Since f37cee996e, we support hashes as versions (instead of timestamps).
This means we can build a hash of the content directly, instead of compiling a
large array with all values that may influence the module content somehow.

Benefits:
* Remove all methods and logic related to querying database and disk for
  timestamps, revision numbers, definition summaries, cache epochs, and more.

* No longer needlessly invalidate cache as a result of no-op changes to
  implementation datails. Due to inclusion of absolute file paths in the
  definition summary, cache was always invalidated when moving wikis to newer
  MediaWiki branches; even if the module observed no actual changes.

* When changes are reverted within a certain period of time, old caches can now
  be re-used. The module would produce the same version hash as before.
  Previously when a change was deployed and then reverted, all web clients (even
  those that never saw the bad version) would have re-fetch modules because the
  version increased.

Updated unit tests to account for the change in version. New default version of
empty test modules is: "mvgTPvXh". For the record, this comes from the base64
encoding of the SHA1 digest of the JSON serialised form of the module content:
> $str = '{"scripts":"","styles":{"css":[]},"messagesBlob":"{}"}';
> echo base64_encode(sha1($str, true));
> FEb3+VuiUm/fOMfod1bjw/te+AQ=

Enabled content versioning for the data modules in MediaWiki core:
* EditToolbarModule
* JqueryMsgModule
* LanguageDataModule
* LanguageNamesModule
* SpecialCharacterDataModule
* UserCSSPrefsModule
* UserDefaultsModule
* UserOptionsModule

The FileModule and base class explicitly disable it for now and keep their
current behaviour of using the definition summary. We may remove it later, but
that requires more performance testing first.

Explicitly disable it in the WikiModule class to avoid breakage when the
default changes.

Ref T98087.

Change-Id: I782df43c50dfcfb7d7592f744e13a3a0430b0dc6
2015-06-18 20:39:38 +00:00
Timo Tijhof
aac831f9fa resourceloader: Use content-neutral context when computing module versions
The startup module produces a manifest with versions representing the
entire module.

Typically, the request for the startup module itself has only=scripts.
However, that "only" must only apply to what resources of the startup module are
output in the request.

The context passed to getModifiedTime() and getVersionHash() must not suggest
any restriction of measuring only the scripts, or otherwise ignoring some
aspects of the module (such as stylesheets, or messages).

Most existing getModifiedTime() implementations compute timestamps of all
files, regardless of the context. So this bug didn't surface before.
However that will change for modules that compute the version hash based on
getModuleContent(), which does honour the getOnly() and shouldIncludeScripts()
methods of the request context.

Change-Id: Ib8f09c39d10724d146b53b6d53d82da18944a12b
2015-06-18 21:10:41 +01:00
umherirrender
d8821f2b0b Fixed spacing
- Removed space after casts
- Removed spaces in array index
- Added spaces around string concat
- Added space after words: switch, foreach
- else if -> elseif
- Removed parentheses around require_once, because it is not a function
- Added newline at end of file
- Removed double spaces
- Added spaces around operations
- Removed repeated newlines

Bug: T102609
Change-Id: Ib860222b24f8ad8e9062cd4dc42ec88dc63fb49e
2015-06-17 20:22:32 +00:00
Kunal Mehta
f6e5079a69 Use mediawiki/at-ease library for suppressing warnings
wfSuppressWarnings() and wfRestoreWarnings() were split out into a
separate library. All usages in core were replaced with the new
functions, and the wf* global functions are marked as deprecated.

Additionally, some uses of @ were replaced due to composer's autoloader
being loaded even earlier.

Ie1234f8c12693408de9b94bf6f84480a90bd4f8e adds the library to
mediawiki/vendor.

Bug: T100923
Change-Id: I5c35079a0a656180852be0ae6b1262d40f6534c4
2015-06-11 18:49:29 +00:00
jenkins-bot
f74244cd13 Merge "resourceloader: Move packaging to a new getModuleContent() method" 2015-06-09 09:13:49 +00:00
Andrew Green
7e0d3369c2 resourceloader: Add context param to ResourceLoaderModule::getDependencies
By providing context as a parameter in getDependencies, we allow
modules to dyanamically determine dependencies based on context.
Note: To ease rollout, the parameter is optional in this patch. It is expected
that it will be made non-optional in the near future.

The use case is for CentralNotice campaigns to be able to add special
modules ahead of deciding which banner to show a user. The dynamically
chosen RL modules would replace ad-hoc JS currently sent with some banners.
A list of possible campaigns and banners is already sent as a PHP-
implemented RL module; that's the module that will dynamically choose other
modules as dependencies when appropriate. This approach will save a round
trip as compared to dynamically loading the modules client-side.

For compatibility, extensions that override
ResourceLoaderModule::getDependencies() should be updated with the new
method signature. Here are changes for extensions currently deployed on
Wikimedia wikis:

* CentralNotice: I816bffa3815e2eab7e88cb04d1b345070e6aa15f
* Gadgets: I0a10fb0cbf17d095ece493e744296caf13dcee02
* EventLogging: I67e957f74d6ca48cfb9a41fb5144bcc78f885e50
* PageTriage: Ica3ba32aa2fc76d11a44f391b6edfc871e7fbe0d
* UniversalLanguageSelector: Ic63e617f51702c27104e123d4bed91983a726b7f
* VisualEditor: I0ac775ca286e64825e31a9213b94648e41a5bc30

For more on the CentralNotice use case, please see I9f80edcbcacca2.

Bug: T98924
Change-Id: Iee61e5b527321d01287baa03ad9b4d4f526ff3ef
2015-06-09 03:10:20 +01:00
Timo Tijhof
5ddd7f91c7 resourceloader: Move packaging to a new getModuleContent() method
Centralise the building of module packages into this method so
that it can be easily re-used.

This is in preparation for providing the option for modules to use
content-based hashing (instead of based on meta-data) in the version
string of modules. Having a getModuleContent method allows that to
be implemented in a way that is well-cached (as we'll be calling it
from multiple multiple code paths) and without duplicating this logic.

Bug: T98087
Change-Id: I376233caaabe44b6101565b70a50904abdf8ab4f
2015-06-09 02:04:58 +01:00
Timo Tijhof
cd0dff5c00 resourceloader: Use mw.log instead of 'throw' for scripts with syntax errors
For scripts loaded from load.php using mw.loader.implement(), an
exception is handled fine and results in the module state progressing
from 'loading' to 'errror'.

However, for wikis modules loaded with only=scripts from the HTML directly,
there is no wrapper. As such, the state() call appended to the script is
never reached and the module indefinitely stays "loading".

VisualEditor (and others) already explicitly ignore the error state
of the wiki modules (with inline mw.loader.using and casting the Promise to resolved).
However in this case the Promise never completed to neither success nor failure.

As such, this was causing users with syntax errors in their user script to
encounter a stuck VisualEditor loading bar that never goes beyond 70%.

Change-Id: I091a020bdd3392b965e0e25d03b216037fadc48f
2015-06-02 22:43:46 +00:00
Gilles Dubuc
d6b4d3c537 Add ability to load plain CSS files at the bottom
Currently all styles modules added to the page using
addModuleStyles are put into the head, regardless
of their "position" value.

Bug: T97420
Change-Id: Ie4287e17d6f298cc63f42f257b1f67ee36961b77
2015-05-25 21:10:14 +00:00
Timo Tijhof
f37cee996e resourceloader: Replace timestamp system with version hashing
Modules now track their version via getVersionHash() instead of getModifiedTime().

== Background ==

While some resources have observeable timestamps (e.g. files stored on disk),
many other resources do not. E.g. config variables, and module definitions.

For static file modules, one can e.g. revert one of more files in a module to a
previous version and not affect the max timestamp.

Wiki modules include pages only if they exist. The user module supports common.js
and skin.js. By default neither exists. If a user has both, and then the
less-recently modified one is deleted, the max-timestamp remains unchanged.

For client-side caching, batch requests use "Math.max" on the relevant timestamps.
Again, if a module changes but another module is more recent (e.g. out-of-order
deployment, or out-of-order discovery), the change would not result in a cache miss.

More scenarios can be found in the associated Phabricator tasks.

== Version hash ==

Previously we virtually mapped these variables to a timestamp by storing the current
time alongside a hash of the value in ObjectCache. Considering the number of
possible request contexts (wikis * modules * users * skins * languages) this doesn't
work well. It results in needless cache invalidation when the first time observation
is purged due to LRU algorithms. It also has other minor bugs leading to fewer
cache hits.

All modules automatically get the benefits of version hashing with this change.
The old getDefinitionMtime() and getHashMtime() have been replaced with dummies
that return 1. These functions are often called from getModifiedTime() in subclasses.

For backward-compatibility, their respective values (definition summary and hash)
are now included in getVersionHash directly.

As examples, the following modules have been updated to use getVersionHash directly.
Other modules still work fine and can be updated later.

* ResourceLoaderFileModule
* ResourceLoaderEditToolbarModule
* ResourceLoaderStartUpModule
* ResourceLoaderWikiModule

The presence of hashes in place of timestamps increases the startup module size on
a default MediaWiki install from 4.4k to 5.8k (after gzip and minification).

== ETag ==

Since timestamps are no longer tracked, we need a different way to implement caching
for cache proxies (e.g. Varnish) and web browsers. Previously we used the
Last-Modified header (in combination with Cache-Control and Expires).

Instead of Last-Modified (and If-Modified-Since), we use ETag (and If-None-Match).

Entity tags (new in HTTP/1.1) are much stricter than Last-Modified by default.
They instruct browsers to allow usage of partial Range requests. Since our responses
are dynamically generated, we need to use the Weak version of ETag.

While this sounds bad, it's no different than Last-Modified. As reassured by
RFC 2616 <http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.3> the
specified behaviour behind Last-Modified follows the same "Weak" caching logic as
Entity tags. It's just that entity tags are capable of a stricter mode (whereas
Last-Modified is inherently weak).

== File cache ==

If $wgUseFileCache is enabled, ResourceLoader uses ResourceFileCache to cache
load.php responses. While the blind TTL handling (during the allowed expiry period)
is still maxage/timestamp based, tryRespondNotModified() now requires the caller to
know the expected ETag.

For this to work, the FileCache handling had to be moved from the top of
ResoureLoader::respond() to after the expected ETag is computed.

This also allows us to remove the duplicate tryRespondNotModified() handling since
that's is already handled by ResourceLoader::respond() meanwhile.

== Misc ==

* Remove redundant modifiedTime cache in ResourceLoaderFileModule.

* Change bugzilla references to Phabricator.

* Centralised inclusion of wgCacheEpoch using getDefinitionSummary. Previously this
  logic was duplicated in each place the modified timestamp was used.

* It's easy to forget calling the parent class in getDefinitionSummary().
  Previously this method only tracked 'class' by default. As such, various
  extensions hardcoded that one value instead of calling the parent and extending
  the array. To better prevent this in the future, getVersionHash() now asserts
  that the '_cacheEpoch' property made it through.

* tests: Don't use getDefinitionSummary() as an API.
  Fix ResourceLoaderWikiModuleTest to call getPages properly.

* In tests, the default timestamp used to be 1388534400000 (which is the unix time
  of 20140101000000; the unit tests' CacheEpoch). The new version hash of these
  modules is "XyCC+PSK", which is the base64 encoded prefix of the SHA1 digest of:
  '{"_class":"ResourceLoaderTestModule","_cacheEpoch":"20140101000000"}'

* Add sha1.js library for client-side hash generation.
  Compared various different implementations for code size (after minfication/gzip),
  and speed (when used for short hexidecimal strings).
  https://jsperf.com/sha1-implementations
  - CryptoJS <https://code.google.com/p/crypto-js/#SHA-1> (min+gzip: 2.5k)
    http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/sha1.js
    Chrome: 45k, Firefox: 89k, Safari: 92k
  - jsSHA <https://github.com/Caligatio/jsSHA>
    https://github.com/Caligatio/jsSHA/blob/3c1d4f2e/src/sha1.js (min+gzip: 1.8k)
    Chrome: 65k, Firefox: 53k, Safari: 69k
  - phpjs-sha1 <https://github.com/kvz/phpjs> (RL min+gzip: 0.8k)
    https://github.com/kvz/phpjs/blob/1eaab15d/functions/strings/sha1.js
    Chrome: 200k, Firefox: 280k, Safari: 78k

  Modern browsers implement the HTML5 Crypto API. However, this API is asynchronous,
  only enabled when on HTTPS in Chromium, and is quite low-level. It requires boilerplate
  code to actually use with TextEncoder, ArrayBuffer and Uint32Array. Due this being
  needed in the module loader, we'd have to load the fallback regardless. Considering
  this is not used in a critical path for performance, it's not worth shipping two
  implementations for this optimisation.

May also resolve:
* T44094
* T90411
* T94810

Bug: T94074
Change-Id: Ibb292d2416839327d1807a66c78fd96dac0637d0
2015-05-19 22:28:17 +00:00
Timo Tijhof
9b6ee1da59 resourceloader: Remove only=messages
This isn't needed.

* Deprecate 'modulemessages' API, return empty result and warning.
* Remove half-implemented only=templates.

Change-Id: Ia6c87d687c6670b3ebf24251572191732651e8f5
2015-05-13 20:17:35 +01:00
Timo Tijhof
f2fee57949 resourceloader: Add logging for T94810
Bug: T94810
Change-Id: Ibedc31659ed91262bca115101136fe60df6c5134
2015-04-24 20:02:46 +00:00
Timo Tijhof
885a1e0703 resourceloader: Simplify getHashMtime() to merely a timestamp
Similar to what getDefinitionMtime() does already. No need to
repeat the hash. No need for an array that needs serialising and
unserialising internally.

Change the hash key to avoid using old cache values.

Also moved the comment about hashes being included in the key to
this method. getDefinitionMtime() is a later method that performs
the same logic but doesn't need the entire story again.

Follows-up 044713c4, d3bdda32.

Change-Id: Idd83de5ac27138a2dbf2ec49d81ea9188bd6ad57
2015-03-31 20:57:07 +00:00
Aaron Schulz
3897868db1 resourceloader: Cut down on file stat time in safeFilemtime()
* If stat cache is not enabled, this used to do two queries.

Change-Id: Icfed675b27f952ec13b9d0af3e345b1486ea7c8f
2015-03-31 17:10:57 +00:00
Timo Tijhof
3e94967191 resourceloader: Simplify log message for getDefinitionMtime() cache miss
* Add quotes around context (which has pipe characters in it).
* Remove hash (not useful).

Change-Id: Iff80c914add0c5a2fe27fff6398bb3384102e3d2
2015-02-20 06:47:06 +00:00
Chad Horohoe
aa21e125a3 Remove obvious function-level profiling
Xhprof generates this data now. Custom profiling of various
sub-function units are kept.

Calls to profiler represented about 3% of page execution
time on Special:BlankPage (1.5% in/out); after this change
it's down to about 0.98% of page execution time.

Change-Id: Id9a1dc9d8f80bbd52e42226b724a1e1213d07af7
2015-01-07 11:14:24 -08:00
Timo Tijhof
6a1ec17e79 resourceloader: Make timestamp handling more consistent
* Use time() instead of:
  - wfTimestamp()
  - wfTimestamp( TS_UNIX )
  - wfTimestamp( TS_UNIX, 0 )
  - wfTimestamp( TS_UNIX, time() )
  - intval( wfTimestamp( TS_UNIX, time() ) )

* Consistently use 1 as default instead of 0. Previously the
  unwritten convention was that anything "final" max()'ed with 1,
  and any internal method would use 0, but this wasn't applied
  consistently made it fragile. There doesn't seem to be any
  value in returning 0 only to have it maxed up to 1 (because if
  the 0 would ever make it out alive, we'd be in trouble).

* wfTimestamp returns a string for TS_UNIX. In PHP this doesn't
  matter much. In fact, max() takes number-like integers so
  transparently, it even preserves it:
  > max( 1, 3, '2' );
  < 3
  > max( 1, '3', 2 );
  < "3"
  Just cast it in one place at the very end (StartupModule)
  instead of doing intval( wfTimestamp() ).

* Fix weird documentation claiming getModifiedTime can return
  an array, or mixed.

* Remove 'version > 1 ? version : 1' logic in
  ResourceLoader::makeLoaderRegisterScript. The client doesn't
  have "0 means now" behaviour so this isn't needed. And the method
  was only doing it for variadic argument calls.

Removal of quotes around timestamps reduced the size of the startup
module from 26.8KB to 25.9KB before gzip. After gzip the size was
and still is 5.7KB, though. (From 5456 bytes to 5415 bytes.)

Change-Id: If92ca3e7511e78fa779f2f2701e2ab24db78c8a8
2014-12-05 21:29:57 +00:00
jdlrobson
ebeb297236 resourceloader: Add support for delivering templates
A base ResourceLoaderModule::getTemplates() exists for subclasses
to override. An implementation is provided for ResourceLoaderFileModule.

For file modules, templates can be specified in the following manner:

'example' => array(
	'templates' => array(
		'bar' => 'templates/foo.html',
	),
	'scripts' => 'example.js',
),

The delivery system is template language agnostic, and currently
only supports "compiling" plain HTML templates.

This also adds template support to the following modules as a POC:
* mediawiki.feedback
* mediawiki.action.view.postEdit
* mediawiki.special.upload

Works with $wgResourceLoaderStorageEnabled

Change-Id: Ia0c5c8ec960aa6dff12c9626cee41ae9a3286b76
2014-10-29 19:31:16 +00:00
Legoktm
de24e3099e Revert "Add RL template module with HTML markup language"
Not ready for merging, and Roan says that the +2 was
most likely accidental and meant to be a -1.

This reverts commit d146934f94.

Change-Id: I3926c9ae9e3c8026fceb3aeedd3b1f1d9b91667b
2014-10-17 23:19:21 +00:00
jdlrobson
d146934f94 Add RL template module with HTML markup language
Preparation work for templating in core.
RL should allow us to ship HTML / template markup from server to client.
Use in Special:Upload and mediawiki.feedback as a proof of concept.
Separation of concerns etc...

See Also:
Ia63d6b6868f23a773e4a41daa0036d4bf2cd6724

Change-Id: I6ff38c12897e3164969a1090449e626001926c3b
2014-10-17 09:23:04 -07:00
umherirrender
c2de24efcd Add missing @param to function docs
Change-Id: Ib7ac94d05a04490f25dfd40b46b27973cbab582c
2014-08-14 19:38:57 +00:00
Kunal Mehta
4b1a87c96e includes/resourceloader/: Use Config instead of globals
Change-Id: Iaa1f4ae9c397575c9bb86dacbc342456e6f5f532
2014-08-07 18:47:34 +01:00
umherirrender
dd8921c9d9 Cleanup some docs (includes/[m-r])
- Swap "$variable type" to "type $variable"
- Added missing types
- Fixed spacing inside docs
- Makes beginning of @param/@return/@var/@throws in capital
- Changed some types to match the more common spelling

Change-Id: I8ebfbcea0e2ae2670553822acedde49c1aa7e98d
2014-07-24 19:43:25 +02:00
Kunal Mehta
126fb8d157 OutputPage: Support foreign module sources in makeResourceLoaderLink
To do so, created ResourceLoader::createLoaderURL(), which takes a
ResourceLoaderContext object. ResourceLoader::makeLoaderURL() was
deprecated.

While reviewing usage of the old function, many of the callers only
differed by one or two parameters from their respective
ResourceLoaderContext object. To simplify that use case, I created
DerivativeResourceLoaderContext, based of off DerivativeContext for
IContextSource.

Change-Id: I961c641ab953153057be3e3b8cf6c07435e9a0b0
2014-07-19 23:44:00 +00:00
Timo Tijhof
75c08916b0 resourceloader: Implement "skip function" feature
A module can be registered with a skip function. Such function,
if provided, will be invoked by the client when a module is
queued for loading. If the function returns true, the client will
bypass any further loading action and mark the module as 'ready'.

This can be used to implement a feature test for a module
providing a shim or polyfill.

* Change visibility of method ResourceLoader::filter to public.

So that it can be invoked by ResourceLoaderStartupModule.

* Add option to suppress the cache key report in ResourceLoader::filter.

We usually only call the minifier once on an entire request
reponse (because it's all concatenated javascript or embedded
javascript in various different closures, still valid as one
large script) and only add a little bottom line for the cache
key. When embedding the skip function we have to run the minifier
on them separately as they're output as strings (not actual
functions). These strings are typically quite small and blowing
up the response with loads of cache keys is not desirable in
production.

* Add method to clear the static cache of ResourceLoader::inDebugMode.

Global static state is evil but, as long as we have it, we at
least need to clear it after switching contexts in the test suite.

Also:
* Remove obsolete setting of 'debug=true' in the FauxRequest in
  ResourceLoaderTestCase. It already sets global wgResourceLoaderDebug
  in the setUp() method.

Bug: 66390
Change-Id: I87a0ea888d791ad39f114380c42e2daeca470961
2014-06-12 03:48:26 +02:00
Siebrand Mazeland
0b2fcf3785 Pass phpcs-strict on includes/resourceloader/
Change-Id: I5c63e0612c2aae240abcdbf21da9cdadd80dee31
2014-05-10 10:39:37 +02:00
Bartosz Dziewoński
62e7156f76 ResourceLoaderModule: Add @since annotations to new methods
Change-Id: I91434fcdc87efdf6d49ec94348f26d20c840abad
2014-05-08 22:26:42 +02:00
umherirrender
dcf6955e5c Fixed some @params documentation (includes/*)
Swapped some "$var type" to "type $var" or added missing types
before the $var. Changed some other types to match the more common
spelling. Makes beginning of some text in captial.

Change-Id: Ifbb1da2a6278b0bde2a6f6ce2e7bd383ee3fb28a
2014-04-20 23:33:05 +02:00
Timo Tijhof
044713c4dc resourceloader: Make sure hashmtime cache key is different by language
We were continuously invalidating the cache for the
ResourceLoaderLanguageDataModule every time a request for a langauge
other than the previous request came in as they all resulted in
the same cache key.

This could be resolved by adding $context->getLang() to the key
(which would be enough for langdata module, but not enough for
other uses of hashmtime), or by adding $context->getHash() (which
will fragment it for all possible context factor combinations,
slightly overkill for most cases, but would work).

Instead resolving it the same way we did in d3bdda3 for a similar
issue in #getDefinitionMtime: by adding the hash itself to the
key. That way it will solve the problem, including two nice things:
* Not fragment anymore than necessary (if it doesn't vary by
  skin, it won't vary by skin, and same for language etc.).
* Always separate keys when the value is different (if something
  can very based on other factors, e.g. LocalSettings globals or
  whatever untracked method may exist for influencing anything,
  it will all work as expected).
* Don't keep alternating and incrementing the timestamp while a
  multi-server infrastructure is syncing code (e.g. old code and
  new code for the same request context will not result in the
  same key and each old/new server alternatingly increasing the
  timestamp, instead the first new server will make the new key
  and the other servers will gradually start finding the new key
  with the timestamp of when it was first seen).

Change-Id: Ifa9088c11c388ca6c912e62efc43494e91702603
2013-12-04 00:56:13 +00:00
Ori Livneh
185d1bc255 Added wfProfileOut for early returns in ResourceLoaderModule::getDefinitionMtime
I added the profiling calls in PS13 of I00cf086c9 but forgot to add
wfProfileOuts for the early returns.

Change-Id: Ibcd22daba8da0e087376553bca271796e0d207e5
2013-12-02 22:10:44 -08:00
Timo Tijhof
d3bdda3221 resourceloader: Add definition hashing to improve cache invalidation
Currently we invalidate module caches based on timestamps from
various places (including message blob, file mtimes and more).

This meant that when a module changes such that the maximum
detectable timestamp is still the same, the cache would not
invalidate.

Module classes can now implement a method to build a summary.
In most cases this should be (a normalised version of) the
definition array originally given to ResourceLoader::register
(such as $wgResourceModules items).

The most common scenarios this addresses:

* File lists (scripts, styles) being re-ordered.
* Files being removed when more recently changed files remain
  part of the module (e.g. removing an older file).
* Files or messages being added to a module while other more
  recently changed things are already part of the module.
  E.g. you create a message and use it in a js file, but forget
  to add the message to the module. Then later you add the msg
  key. This last update would be ignored, because the mtime of
  the message is no newer than the total which already included
  the (same) mtime of the js file added in the previous update.
* Change the concatenation order of pages in a Gadget definition.

Bug: 37812
Change-Id: I00cf086c981a84235623bf58fb83c9c23aa2d619
2013-12-02 21:45:33 -08:00
Timo Tijhof
339ca89b18 resourceloader: Support hashes as cache invalidation trigger
For now ResourceLoader will still internally deal with timestamps,
especially because they are easier to max() on the client side
(on the server we could make a hash of different hashes, on the
client that's a bit annoying).

However ResourceLoaderModule#getHashMtime will abstract the logic
we already use in ResourceLoaderLanguageDataModule and have
encouraged others to use, which is to put the timestamp and
hash in Memcached, and use that to observer the hash change and
update the timestamp when it does.

Updated ResourceLoaderLanguageDataModule to make use of this.

Change-Id: Ib051ef41ba239084671c30fd275b8d94099d5d52
2013-10-07 23:00:38 +02:00
Max Semenik
5c51cb96ea Maintenance script to check LESS files for validity
A reworked version of script from I068686854ad79e2f63a08d81b1af02f373110613

Move leccs instantiation code to ResourceLoader because it doesn't depend on any
particular module's state.

Change-Id: I733b53171dca77f50a30e5bd0bd5f1b456e4c85d
2013-09-30 21:37:13 +04:00
Timo Tijhof
93cb656139 less: Use new addParsedFile method, replacing embeddedFiles hack
Follows-up b67b9e1, lessphp now has a public method to add to the
list of files for compilation cache.

Change-Id: I62a6c7cdeb34ea742fa7547e3ca10e24ee484b97
2013-09-29 05:16:00 +00:00
Timo Tijhof
e09c4d952d less: Add '@since 1.22' comments
Change-Id: I673705423cf7618e207c0ee47b01761d6c89ce5f
2013-09-28 06:23:01 +00:00
Ori Livneh
565b0fae81 Rename lessc->embeddedImages to lessc->embeddedFiles
'embeddedImages' is a custom property we set on lessc compiler instances to
track the set of files that were embedded in the generated source as data URIs.
This is so done so we know to regenerate the CSS if the source file for an
embedded asset changes. (If my pull request[1] is merged, we won't have to use
a custom property at all.)

I realized that the property name should be 'embeddedFiles' rather than
'embeddedImages', because it's not just images that can be usefully embedded in
CSS, but fonts as well.

  [1]: https://github.com/leafo/lessphp/pull/472

Change-Id: Ief3afaa23e4532f4a536e0dfef943d4fa20db80d
2013-09-23 14:46:41 -07:00
Ori Livneh
b67b9e1b48 Support LESS stylesheets in ResourceLoader
This patch adds support for the LESS stylesheet language to ResourceLoader.
LESS is a stylesheet language that compiles into CSS. The patch includes
lessphp, a LESS compiler implemented in PHP. The rationale for choosing LESS is
explained in a MediaWiki RFC which accompanies this patch, available at
<https://www.mediawiki.org/wiki/Requests_for_comment/LESS>.

LESS support is provided for ResourceLoader file modules. It is triggered by
the presence of the '.less' extension in stylesheet filenames. LESS files are
compiled by lessc, and the resultant CSS is subjected to the standard set of
transformations (CSSJanus & CSSMin). The immediate result of LESS compilation
is encoded as an array, which includes the list of LESS files that were
compiled and their mtimes. This array is cached. Cache invalidation is
performed by comparing the cached mtimes with the mtimes of the files on disk.
If the compiler itself throws an exception, ResourceLoader constructs a
compilation result which consists of the error message encoded as a CSS
comment. Failed compilation results are cached too, but with an expiration time
of five minutes. The expiration time is required because the full list of
referenced files is not known.

Three configuration variables configure the global environment for LESS
modules: $wgResourceLoaderLESSVars, $wgResourceLoaderLESSFunctions, and
$wgResourceLoaderLESSImportPaths. $wgResourceLoaderLESSVars maps variable names
to CSS values, specified as strings. Variables declared in this array are
available in all LESS files. $wgResourceLoaderLESSFunctions is similar, except
it maps custom function names to PHP callables. These functions can be called
from within LESS to transform values. Read more about custom functions at
<http://leafo.net/lessphp/docs/#custom_functions>. Finally,
$wgResourceLoaderLESSImportPaths specifies file system paths in addition to the
current module's path where the LESS compiler should look up files referenced
in @import statements.

The issue of handling of /* @embed */ and /* @noflip */ annotations is left
unresolved. Earlier versions of this patch included an @embed analog
implemented as a LESS custom function, but there was enough ambiguity about
whether the strategy it took was optimal to merit discussing it in a separate,
follow-up patch.

Bug: 40964
Change-Id: Id052a04dd2f76a1f4aef39fbd454bd67f5fd282f
2013-09-23 12:55:19 -07:00
Ori Livneh
71e7e64001 Consistently follow conventions for documenting parameters
Per MW:CC/PHP, the type goes before the variable name, and built-in types are
not uppercase.

Change-Id: Ibb753acd9529ace3579d57654adc47673fa49719
2013-09-12 21:50:45 -07:00
Matthew Flaschen
5b212601db Remove comment saying code should add RL dependencies directly
This does not reflect actual ResourceLoader best practices.

Bug: 51853
Change-Id: I62e875c472ecc54b310ce5ed14fdcabda02e19e5
2013-08-22 17:50:26 +00:00
Timo Tijhof
8dbe77db6c phpcs: Pass includes/resourceloader/
- A cast statement must not be followed by a space.
- The method parameter $context is never used.
- Avoid function calls in a FOR loop test part.
- Opening brace should be on the same line as closing parenthesis.

Change-Id: I0eba7fcc9ceab372003d1134857346690c525e87
2013-04-03 02:16:02 +02:00
Yuri Astrakhan
9506e3d812 Spellchecked /includes directory
* Ran spell-checker over code comments in /includes/
* A few spellchecking fixes for wfDebug() calls

Found one very strange (NOOP?) line in Linker.php - see "TODO: BUG?"

Change-Id: Ibb86b51073b980eda9ecce2cf0b8dd33f058adbf
2013-03-13 03:42:41 -04:00
Tyler Anthony Romeo
4dcc7961df Fixed @param tags to conform with Doxygen format.
Doxygen expects parameter types to come before the
parameter name in @param tags. Used a quick regex
to switch everything around where possible. This
only fixes cases where a primitve variable (or a
primitive followed by other types) is the variable
type. Other cases will need to be fixed manually.

Change-Id: Ic59fd20856eb0489d70f3469a56ebce0efb3db13
2013-03-11 13:15:01 -04:00
umherirrender
d63121016d fix some spacing
Added/removed spaces around logical/arithmetic operator
Reduced multiple empty lines to one empty line
Removed wrong tabs before comments at end of line
Removed too many spaces in assigments

Change-Id: I2bba4e72f9b5f88c53324d7b70e6042f1aad8f6b
2013-03-07 17:53:21 +01:00
Juliusz Gonera
c2d117b379 Add mobile target to modules needed for mw.msg()
This changes allows us to use mw.msg() in MobileFrontend.

Change-Id: I446656bcc17a31d23da054a6e1154f3e5823fbf5
2012-12-17 16:24:02 -08:00
Timo Tijhof
799db0b44b ResourceLoader: Move safeFilemtime() to ResourceLoaderModule.
This is a useful method not just for inside and sub classes of
ResourceLoaderFileModule (i.e. it could've been useful in
VisualEditor's ResourceLoaderModule class as well)

Also moved up getTargets() to be in the right section (looking at
the file as a whole).

Change-Id: If696ffbdc5aa7f0a51603bcf9d52adab38b9c686
2012-12-16 23:13:04 +01:00
Ori Livneh
56831e1f9e Fix typo (manuall -> manually)
Change-Id: Ia6101ea84faf9a4420afe9568b5e3904fffa61b1
2012-11-19 02:18:27 -08:00
Ori Livneh
6179de561b Fix typo (ResourceLodaer => ResourceLoader)
Change-Id: Ie349853f3fbcd7a9eb038d5988497f115684ebeb
2012-11-12 20:18:59 -08:00
umherirrender
9d19d7342a Remove a bunch of trailing spaces and unneeded newlines
Change-Id: I7db616db8c969567d420c0161fa207b366e292b6
2012-10-19 22:03:05 +02:00
Brion Vibber
4b3a426ae0 Work in progress on ResourceLoader mobilification
Goes along with MobileFrontend changes: https://gerrit.wikimedia.org/r/28434

Adds 'targets' option to module definitions, defaulting to 'desktop'.
Only a couple more modules are whitelisted into both desktop and mobile for now.

Startup module takes a 'target' parameter (defaults to 'desktop') to filter
the resource module registration list. Only modules matching the filter get
registered, and thus will be loadable from client-side RL.

Change-Id: Ifb772d4995b8e2ec4b63776fe0bb5b0214f82e04
2012-10-18 00:55:54 +00:00
Siebrand
766ed469cf Merge "Stylize" 2012-10-03 14:49:22 +00:00
Timo Tijhof
ff594d3b0a ResourceLoader: Refactor style loading
Fixes:
* bug 31676: Work around IE stylesheet limit.
* bug 35562: @import styles broken in modules that combine
  multiple stylesheets.
* bug 40498: Don't output empty "@media print { }" blocks.
* bug 40500: Don't ignore media-type for urls in debug mode.

Approach:
* Re-use the same <style> tag so that we stay under the 31
  stylesheet limit in IE. Unless the to-be-added css text from
  the being-loaded module contains @import, in which case we do
  create a new <style> tag and then re-use that one from that
  point on (bug 31676).

* Return stylesheets as arrays, instead of a concatenated string.
  This fixes bug 35562, because @import only works when at the
  top of a stylesheet. By not unconditionally concatenating files
  within a module on the server side already, @import will work
  in e.g. module 'site' that contains 2 wiki pages.

  This is normalized in ResourceLoader::makeCombinedStyles(),
  so far only ResourceLoaderWikiModule makes use of this.

Misc. clean up and bug fixes:
* Reducing usage of jQuery() and mw.html.element() where
  native DOM would be very simple and faster. Aside from
  simplicity and speed, this is also working towards a more
  stand-alone ResourceLoader.
* Trim server output a little bit more
  - Redundant new line after minify-css (it is now an array, so
    no need to keep space afterwards)
  - Redundant semi-colon after minify-js if it ends in a colon
* Allow space in styleTest.css.php
* Clean up and extend unit tests to cover for these features
  and bug fixes.
* Don't set styleEl.rel = 'stylesheet'; that has no business
  on a <style> tag.
* Fix bug in mw.loader's addStyleTag(). It turns out IE6
  has an odd security measure that does not allow manipulation
  of elements (at least style tags) that are created by a
  different script (even if that script was served from the same
  domain/origin etc.). We didn't ran into this before because
  we only created new style tags, never appended to them. Now
  that we do, this came up. Took a while to figure out because
  it was created by mediawiki.js but it calls jQuery which did
  the actual dom insertion. Odd thing is, we load jquery.js and
  mediawiki.js in the same request even...
  Without this all css-url related mw.loader tests would fail
  in IE6.
* mediawiki.js and mediawiki.test.js now pass jshint again.

Tested (and passing qunit/?module=mediawiki; 123 of 123):
* Chrome 14, 21
* Firefox 3.0, 3.6, 4, 7, 14, 15, 16beta
* IE 6, 7, 8, 9
* Safari 4.0, 5.0, 5.1
* Opera 10.0, 11.1, 11.5, 11.6, 12.0, 12.5beta
* iPhone 3GS / iOS 3.0 / Mobile Safari 4.0
  iPhone 4 / iOS 4.0.1 / Mobile Safari 4.0.5
  iPhone 4S / iOS 6.0 Beta / Mobile Safari 6.0

Change-Id: I3e8227ddb87fd9441071ca935439fc6467751dab
2012-10-03 00:23:16 +02:00
jeroendedauw
1ccaff3ee8 Stylize
Change-Id: Ia9532f06db8331da1ea5ff9c9398073d7d084484
2012-10-01 12:36:15 +02:00
jeroendedauw
e1101bbb6f Style fix
Change-Id: I6b900924b07b44152fa943d10400fe151b4046c8
2012-09-27 21:36:14 +02:00
Antoine Musso
aab43dd495 escape tags and entity in doxygen comments
When inserting XML elements inline <such as this one>, doxygen chokes
about it not being known. Simply enclosing the tag in double quotes
prevents doxygen from emitting a warning.

Also enclosed a few invalid functions calls such as \. and double quoted
the HTML entities such as &foobar;

Change-Id: I4019637145e683c2bec3d17b2fd98b0c50a932f1
2012-07-10 17:08:32 +02:00
Max Semenik
cd7923ac16 Introduced the concept of raw ResourceLoader modules
This is needed for mobile scripts that are supposed to work on dumb
devices and as such can't rely on client-side RL, but still can take
advantage of server-side minification and concatenation.

Patchset 2: Allow loading raw modules with &raw=true appended to URL.

Change-Id: I9410ffbf6633075e07bd06b10a98a4d12d9b6106
2012-05-16 01:03:12 +04:00
Alexandre Emsenhuber
7d9016943d Added missing GPLv2 headers in some places.
Also made file/class documentation more consistent.

Change-Id: I1815587ab2eeb24623ce4bf1c695088bd3f1c2ea
2012-04-30 09:16:10 +02:00
Roan Kattouw
beb7ab0f36 (bug 35036) Wikipage-based ResourceLoader modules were not automatically purged as they should be when one of their messages changed. In practice, this only affected WikiLove.
Also adding a documentation comment in ResourceLoaderModule to clarify that it is the subclass's responsibility to make sure message blob timestamps are taken into account
2012-03-07 19:33:37 +00:00
Sam Reed
f8a0e34ca1 Documentation
Trim trailing whitespace

Make returns return values where appropriate (ie other paths in the same method do)
2011-10-14 08:06:54 +00:00
Roan Kattouw
488d368b86 Followup r96978, clean up code duplication by factoring out the code building load.php requests into ResourceLoader::makeLoaderURL() and makeLoaderQuery() 2011-09-13 20:36:24 +00:00
Roan Kattouw
f4f3107209 Fix the fixme on r88053: dependency handling was broken in debug mode in certain cases. More specifically, if A is a file module that depends on B, B is a wiki module that depends on C and C is a file module, the loading order is CBA (correct) in production mode but was BCA (wrong) in debug mode. Fixed this by URL-ifying scripts and styles for those modules in debug mode, as I said to on CR. What this means is that the initial debug=true request for a module will now always return arrays of URLs, never the JS or CSS itself. This was already the case for file modules (which returned arrays of URLs to the raw files), but not for other modules (which returned the JS and CSS itself). So for non-file modules, load.php?modules=foo&debug=true now returns some JS that instructs the loader to fetch the module's JS from load.php?modules=foo&debug=true&only=scripts and the CSS from ...&only=styles .
* Removed the magic behavior where ResourceLoaderModule::getScripts() and getStyles() could return an array of URLs where the documentation said they should return a JS/CSS string. Because I didn't restructure the calling code too much, the old magical behavior should still work.
* Instead, move this behavior to getScriptURLsForDebug() and getStyleURLsForDebug(). The default implementation constructs a single URL for a load.php request for the module with debug=true&only=scripts (or styles). The URL building code duplicates some things from OutputPage::makeResourceLoaderLink(), I'll clean that up later. ResourceLoaderFileModule overrides this method to return URLs to the raw files, using code that I removed from getScripts()/getStyles()
* Add ResourceLoaderModule::supportsURLLoading(), which returns true by default but may return false to indicate that a module does not support loading via a URL. This is needed to respect $this->debugRaw in ResourceLoaderFileModule (set to true for jquery and mediawiki), and obviously for the startup module as well, because we get bootstrapping problems otherwise (can't call mw.loader.implement() when the code for mw.loader isn't loaded yet)
2011-09-13 17:13:53 +00:00
Krinkle
cc21627b4d [ResourceLoader 2]: Add support for multiple loadScript sources
Front-end:
* New mw.loader method: addSource(). Call with two arguments or an object as first argument for multiple registrations
* New property in module registry: "source". Optional for local modules (falls back to 'local'). When loading/using one or more modules, the worker will group the request by source and make separate requests to the sources as needed.
* Re-arranging object properties in mw.loader.register to match the same order all other code parts use.
* Adding documentation for 'source' and where missing updating it to include 'group' as well.
* Refactor of mw.loader.work() by Roan Kattouw and Timo Tijhof:'
-- Additional splitting layer by source (in addition to splitting by group), renamed 'groups' to 'splits'
-- Clean up of the loop, and removing a no longer needed loop after the for-in-loop 
-- Much more function documentation in mw.loader.work()
-- Moved caching of wgResourceLoaderMaxQueryLength out of the loop and renamed 'limit' to 'maxQueryLength

Back-end changed provided through patch by Roan Kattouw (to avoid broken code between commits):
* New method in ResourceLoader: addSource(). During construction of ResourceLoader this will be called by default for 'local' with loadScript property set to $wgLoadScript. Additional sources can be registered through $wgResourceLoaderSources (empty array by default)
* Calling mw.loader.addSource from the startup module
* Passing source to mw.loader.register from startup module
* Some new static helper methods

Use:
* By default nothing should change in core, all modules simply default to 'local'. This info originates from the getSource()-method of the ResourceLoaderModule class, which is inherited to all core ResourceLoaderModule-implementations (none override it)
* Third-party users and/or extensions can create new classes extending ResourceLoaderModule, re-implementing the getSource-method to return something else.

Basic example:
$wgResourceLoaderSources['mywiki'] = array( 'loadScript' => 'http://example.org/w/load.php' );
class MyCentralWikiModule extends ResourceLoaderModule {
	function getSource(){
		return 'mywiki';
	}
}
$wgResourceModules['cool.stuff'] => array( 'class' => 'MyCentralWikiModule' );

More complicated example
// imagine some stuff with a ForeignGadgetRepo class, putting stuff in $wgResourceLoaderSources in the __construct() method
class ForeignGadgetRepoGadget extends ResourceLoaderModule {
	function getSource(){
		return $this->source;
	}
}

Loading:
Loading is completely transparent, stuff like $wgOut->addModules() or mw.loader.loader/using both take it as any other module and load from the right source accordingly.


--
This commit is part of the ResourceLoader 2 project.
2011-07-26 21:10:34 +00:00
Brion Vibber
0f201b19f4 * (bug 28626) Validate JavaScript files and pages loaded via ResourceLoader before minification, protecting separate modules from interference
This is possibly not perfect but seems to serve for a start; follows up on r91591 that adds JSMin+ to use it in some unit tests. May want to adjust some related bits.

- $wgResourceLoaderValidateJs on by default (can be disabled)
- when loading a JS file through ResourceLoaderFileModule or ResourceLoaderWikiModule, parse it using JSMinPlus's JSParser class. If the parser throws an exception, the JS code of the offending file will be replaced by a JS exception throw listing the file or page name, line number (in original form), and description of the error from the parser.
- parsing results are cached based on md5 of content to avoid re-parsing identical text
- for JS pages loaded via direct load.php request, the parse error is thrown and visible in the JS console/error log

Issues:
- the primary use case for this is when a single load.php request implements multiple modules via mw.loader.implement() -- the loader catches the exception and skips on to the next module (good) but doesn't re-throw the exception for the JS console. It does log to console if present, but it'll only show up as a regular debug message, not an error. This can suppress visibility of errors in a module that's loaded together with other modules (such as a gadget).
- have not done performance testing on the JSParser
- have not done thorough unit testing with the JSParser
2011-07-06 21:48:09 +00:00
Sam Reed
16c194d0ae Fixup/add documentation
Remove trailing whitespace
2011-05-21 17:45:20 +00:00
Roan Kattouw
82bf4764ea For bug 27488: move the startup script, jquery+mediawiki and the mw.config.set() call for configuration variables back to the <head> . Let modules control whether they're loaded in the <head> ('top') or at the bottom of the <body> ('bottom') through the position parameter/property
Also rearranges the loading order a little bit such that only=messages comes before only=scripts, and config comes before everything except startup and jquery+mediawiki
2011-04-07 12:07:25 +00:00
Roan Kattouw
246362f8c2 Fix default implementation of ResourceLoaderModule::getStyles() to return an array, not a string. Was causing problems with another function that was being fed the return value of getStyles() and used an array type hint 2011-03-27 14:13:57 +00:00
Sam Reed
757750dcac Remove getFlip code duplication
Move usual one into ResourceLoaderModule, and then move what was in ResourceLoaderModule into ResouceLoaderFileModule
2011-03-25 11:15:40 +00:00
Roan Kattouw
880f09b10c (bug 27302) Avoid unnecessary requests for user and site modules if the relevant wiki pages don't exist.
Done by adding isKnownEmpty() to ResourceLoaderModule and overriding it to check for page existence in ResourceLoaderWikiModule. Needed to rearrange some code in OutputPage::makeResourceLoaderLink() to have the emptiness check and dropping of modules work properly. Also factored the page_touched check in ResourceLoaderWikiModule::getModifiedTime() out to a separate method (getTitleMtimes()) and moved in-object caching there as well, so getModifiedTime() and isKnownEmpty() share code and caching for their timestamp/existence checks.

This does not account for the case where e.g. a user has user CSS but no user JS: I had implemented this by checking for $context->getOnly() in getTitleMtimes(), but then realized it's not safe to do this in a function called by getModifiedTime(): it causes the timestamp list in the startup module to only take scripts in account for wiki modules, because the startup module has &only=scripts set
2011-02-19 17:07:05 +00:00
Sam Reed
c0830dd868 2 subclasses of ResourceLoaderWikiModule implement a duplicate version of getFlip. Move it up into ResourceLoaderWikiModule
(Almost looks like it could all go into ResourceLoaderModule... But that uses a different version, seemingly, the only one. 3 other subclasses of ResourceLoaderModule implement the same version of getFlip as is moved into a parent class here... Seems daft to have a different version in the base abstract class... Minor oversight?)

Some documentation
2011-02-18 00:33:45 +00:00
Roan Kattouw
c38e2e499c Fixes for r81936 per Tim's review 2011-02-11 08:29:55 +00:00
Roan Kattouw
370d700dd6 Fix getMsgBlobMtime() to also cause a cache invalidation if a module has messages but no stored message blob 2011-02-11 08:07:47 +00:00
Krinkle
dfb5beb89d user scripts & styles are lowercase skin; + using 'vector' as example instead. 2011-02-04 16:44:07 +00:00
Happy-melon
da36f65433 Follow-up r64670 (bug22929): cleaner implementation of security for script (and potentially CSS) files. ResourceLoader *already* knows where each module has come from, so all we need to do is filter them in OutputPage according to the desired level of 'trustworthiness'.
TODO:
* Are there instances where we might want to restrict CSS as well as JS?
* Would a $wg config option and/or user preference and/or index.php GET parameter to limit inclusion be useful?
* Can we deprecate any of the existing $wg config options?
* What's going on with the duplicated code between OutputPage and SkinTemplate?
2011-02-04 16:39:17 +00:00
Sam Reed
b2bfcc788a Documentation addition/tweaks 2011-01-10 04:44:33 +00:00
Tim Starling
ec2acb239b * In ResourceLoaderContext, lazy-load $this->direction and $this->language, to avoid loading the whole English localisation for load.php requests which never call getHash().
* Interpreted some Trevor-speak in the doc comment of ResourceLoader::preloadModuleInfo().
* Made setMsgBlobMtime() (called from preloadModuleInfo()) actually work, by making getMsgBlobMtime() use the cached blob times if they are available.
2010-11-19 06:52:38 +00:00
Trevor Parscal
c519873cdc Fixed Doxygen incompatible JSDoc style comments (bad Trevor!) as per some comments on r75036. 2010-11-05 18:33:50 +00:00
Tim Starling
06b2b1bd66 Resource loader minor changes. Fix for r73668 etc.
* Break long lines.
* Convert long or unnecessary ternary operator usages to if/else.
* Fixed excessively clever assignment expressions.
* Rename $cache to $cacheEntry.
* Removed unnecessary web invocation guards. Their perlish form was making me uncomfortable. BTW, unlike in Perl, die() is not a function, it's a special case in the PHP grammar which very roughly simulates the Perl syntax:

die "x"; // works
0 || die("x"); // works
0 || (die); // works
0 || (die "x"); // fail!
2010-11-03 07:58:03 +00:00
Trevor Parscal
70bae52c12 Part 2 of 2, moved ResourceLoader*Module classes to their own files - this commit removes the non file specific code. 2010-10-19 18:31:09 +00:00
Trevor Parscal
ef6baa91de Moved ResourceLoader classes to their own folder, preparing to also split ResourceLoaderModule.php into multiple files (it's getting a bit long now) 2010-10-19 18:21:38 +00:00
Renamed from includes/ResourceLoaderModule.php (Browse further)