Rationale
This is a bit of clean-up for a couple reasons. (The below has since been documented in coding conventions and performance guidelines.
Finding files
Make it easier to find files in the repository based on their module name. This applies to features like "Find File" in text editors (eg. ⌘+P / ⌃+P in Atom and Sublime Text), as well as to repository viewers (eg. T on GitHub).
Contributing
Even in our current core stack (with good ol' ResourceLoader concatenating files), there's a fair amount of complexity that can overwhelm new contributors. And even for experienced contributors, we don't all work with all files all the time. So being able to easily tell which (other) files load as part of a given module is quite useful.
I would expect this to reduce overall confusion, but also reduce risk of forgetting to declare dependencies between related code paths (given files in the same directory but part of separate modules). It would also make it easier to create something in less feedback cycles of "try this", "get an error" (eg. for cases where we do detect something is broken, missing dependencies tends to not be one of them, though).
Performance
Quantify the cost of modules through visibility in the directory structure, hopefully making it easier and clearer how and where to add new code to the same module, and to discover which code is and isn't already included in the same bundle.
Past
Some past work has been put in towards this, but so far only in certain sub-trees. Never across the board.
Some past conversions in resources/src/
- https://gerrit.wikimedia.org/r/161765 (2014)
- rMW0bfdd927beb0: Restructure /resources/src/mediawiki.api/ (2015)
- rMW648667ac9f08: Split /resources into /resources/lib and /resources/src
Also, we've been doing fairly well in resources/lib/ where every module has its own directory now, yay!
Future
This will also get things in a better shape of the future that awaits us in T133462, where it'll likely become a prerequisite for a module to either be one file, or be its own directory. Even if we don't enforce that, it'd be even more confusing than today if we have files importing each other using require('./example'); but also have files in the same directory that aren't reachable as part of the module.
Proposal
The proposal is the following two mandates:
Currently fine as-is
- "jquery.chosen" is at resources/lib/jquery.chosen/
- "moment" is at resources/lib/moment/
- "qunit" is at resources/lib/qunitjs/
- "jquery.tipsy" is at resources/src/jquery.tipsy/
- "mediawiki.toolbar" is at resources/src/mediawiki.toolbar/
- "mediawiki.widgets.datetime" is at resources/src/mediawiki.widgets.datetime/
- "startup" is at resources/src/startup.js
Examples to change
- resources/lib/jquery/
This directory contains things loosely related to "jQuery" in some way or another, registered as multiple different modules. The ones that are single-file modules could be moved up to be in lib/ directory. The others should get their own directory. Leaving jquery/ to only contain jquery.js and jquery.migrate.js – the contents of the module currently registered as "jquery".
- resources/src/mediawiki/
- api.js
- api/
- category.js
- htmlform/
- page/
- ready.js
- startup.js
- watch.js
This the "api" and "page" are remnants of my attempt to make the directory structure reflect the run-time class hierarchy (instead of the module/bundle structure). This is also predates things like module.exports.
The idea was to roughly be able to translate a public identifier in JavaScript (e.g. mw.Api.prototype.isCategory or mw.page.watch.updateLinks()) to a path on the file system. I didn't think about this well, and I regret doing it. It didn't work because the way we namespace our modules is by module name, not my namespace hierarchy. Even in the above examples we can see a few clear flaws and limitations:
- mediawiki/api/category.js does not translate to mw.api.category = {}. Rather it translates to the module name mediawiki.api.category. The actual identifier is mw.Api and several methods such as mw.Api#isCategory.
- mediawiki/page/watch.js - This was at some point the first and only module to justify my (bad) idea. We did have mw.page.watch. It existed. But it doesn't exist anymore. And the other files in the directory mostly don't have any public identifiers. They're just run-time logic with their file reflecting the module names: mediawiki.page.startup, mediawiki.page.ready, etc.
Given that all of these are single-file modules, there are two ways we could solve them:
- Put them directly in resources/src/ as mediawiki.api.category.js and mediawiki.page.ready.js.
- Give some of the related modules their own shared directory, e.g. resources/src/mediawiki.api/ and resources/src/mediawiki.page/, with the single-file modules living inside of it.
Both of these would satisfy the two proposed mandates.
Progress
Below listing is based on the structure as it was when we started.
Reference: https://gerrit.wikimedia.org/g/mediawiki/core/+/42956b99b558294e5aa8c6c0e2a8f18513478022/resources/
Items are checked off when the file or directory has been checked recursively to match the above two principles (and renamed or split as needed).
resources/lib/
- CLDRPluralRuleParser/
- html5shiv/
- jquery/
- jquery.chosen/
- jquery.client/
- jquery.i18n/
- jquery.ui/ – T219604
- moment/
- mustache/
- oojs-router/
- oojs-ui/
- oojs/
- qunitjs/
- sinonjs/
resources/src/
- jquery.tipsy/
- jquery/
- jquery.color
- jquery.confirmable
jquery.hidpi(removed)- jquery.lengthLength
- jquery.makeCollapsible
- jquery.farbtastic
- jquery.tablesorter
- jquery.spinner
- (misc)
- mediawiki.action/
- mediawiki.hidpi-skip.js
- mediawiki.language/
- mediawiki.legacy/
mediawiki.less/(less importdir: not a module)- mediawiki.libs.jpegmeta/
- mediawiki.libs.pluralruleparser/
- mediawiki.messagePoster/
- mediawiki.rcfilters/
- mediawiki.router/
- mediawiki.skinning/
- mediawiki.special/
- mediawiki.toolbar/
- mediawiki.ui/
- mediawiki.widgets.datetime/
- mediawiki.widgets.visibleLengthLimit/
- mediawiki.widgets/
- mediawiki/
- mediawiki/api/
- mediawiki/htmlform/
- mediawiki/page/
- moment/
- startup.js
Follow-up
See T192623 further about these.