Page MenuHomePhabricator

[Spike] How should we load Vue.js and dependencies for Vue.js search?
Closed, ResolvedPublicSpike

Description

The new Vue.js search will have at least the following dependencies:

  • Presentation styles
  • Client-only JavaScript
  • Vue.js itself (via Core's ResourceLoader module T252348)

It's expected that Vue.js will be the lion's share at 64 kilobytes minified for the runtime only which is a significant increase in page size. The runtime + compiler is 91 kilobytes minified. According to present desktop dashboards, the current JavaScript payload is 216 kilobytes.

How should we load all this code? E.g., as a ResourceLoader module dependency in skin.json or defer loading until after initial render? On input? Something else? That's what this task identifies.

Conclusions

  • The search widget is lazy-loaded upon first interaction currently. At that point, it's mainly a matter of how much (if any) technical debt to incurr and/or how many module bundles to create. This approximates the loading strategy for the old search.

Acceptance criteria

Related Objects

Event Timeline

Restricted Application changed the subtype of this task from "Task" to "Spike". · View Herald TranscriptApr 3 2020, 5:02 AM
Restricted Application added a subscriber: Aklapper. · View Herald Transcript
Niedzielski updated the task description. (Show Details)Apr 3 2020, 5:07 AM
Niedzielski renamed this task from [Spike] How should we share dependencies? to [Spike] How should we share and load dependencies?.Apr 3 2020, 2:53 PM
Niedzielski updated the task description. (Show Details)
Niedzielski renamed this task from [Spike] How should we share and load dependencies? to [Spike] How should we share and load dependencies for Vue.js search?.Apr 5 2020, 4:23 PM
Niedzielski updated the task description. (Show Details)Apr 15 2020, 1:29 AM
Niedzielski added a subscriber: Volker_E.
Niedzielski updated the task description. (Show Details)May 4 2020, 9:36 PM
ovasileva triaged this task as Medium priority.May 7 2020, 5:23 PM
Niedzielski renamed this task from [Spike] How should we share and load dependencies for Vue.js search? to [Spike] How should we load Vue.js and dependencies for Vue.js search?.May 11 2020, 2:46 AM
Niedzielski added a project: Performance-Team.
Niedzielski updated the task description. (Show Details)

Removed:

  • How do we load only the relevant search implementation for the configuration? mediawiki.searchSuggest is needed for the Legacy mode and Vue.js + the new search form itself will be needed for Latest (see T249051). They should not be both loaded.

Covered by T250851.

Removed:

  • If Webpack is used, do we want or need to split the runtime out for sharing? If two projects are using Webpack (e.g., Popups), are there any conflicts to be aware of? Do we need any test infrastructure for ensuring versions match? (E.g., if Popups and Vector are installed, require the package.json files of both and check that the major and minor versions match.)

This implies a unified build process which is out of scope.

Removed:

  • How can we depend on Vue? Are there any concerns on simply using the Core ResourceLoader module (comes in both dev and prod flavors)?

Covered by T252348.

Removed:

  • Do we anticipate other libraries will be needed in the runtime? Do all of these get pushed into Core? The only unusual dependency I see in Popups and MobileFrontend are redux* and Vuex probably won't be needed for search.
  • If two projects have the same dependencies, how are those shared in the context of ResourceLoader?

Let's assume the simplest case for the search project. We can add a RL module or a vendor entry for shared resources as needed.

Gilles assigned this task to Krinkle.May 20 2020, 4:27 PM
Gilles moved this task from Inbox to Doing on the Performance-Team board.May 20 2020, 4:29 PM
Niedzielski updated the task description. (Show Details)May 21 2020, 7:19 PM
Krinkle updated the task description. (Show Details)May 25 2020, 5:13 PM

How should we load all this code? E.g., as a ResoureLoader module dependency in skin.json or defer loading until after initial render? On input? Something else? That's what this task identifies.

The search widget is lazy-loaded upon first interaction currently. I would expect this to remain the case. At that point, it's mainly a matter of how much (if any) technical debt to incurr and/or how many module bundles to create.

The simplest and least compromising approach I see at the moment would be to use skinScripts in mediawiki.page.ready (to change the loading logic), and then have a single module in Vector for the search widget, which would naturally dependen Vue.

The logic override could even be avoided if we normalise/ingrain this further by considering search as a first-class citizen in the skin system as something that can be overriden. I see three possible options there:

  • Let skins redefine the mediawiki.searchSuggest module in its entirety. This would go a step further than skinScripts, as it would allow you to also replace messages and dependencies. This would work similarly to what we do with MessagePosterModule and QUnitTestModule in skin.json/extension.json today. The definition of the current skin would automatically be used by ResourceLoader (with the current version as default).
    • Standard is the mediawiki.searchSuggest name.
    • Benefit: No changes to mediawiki.page.ready.
    • Downside: Module definition would be in a different key from other modules in the skin.json file.
  • Let skin.json control which module name is used by mediawiki.page.ready. E.g. in skin.json there could be an attribute like SkinSearchModuleName which would default to mediawiki.searchSuggest, but it could be overridden in Vector to skin.vector.search or some such.
    • Standard: The skin.json attribute.
    • Benefit: Module is defined normally. No magic module name. No changes to mediawiki.page.ready.
    • Downside: Requires an extra module in most cases, but that might be okay. (Especially after the additional budget cleared from T253582).
  • Let the Skin cllass control which module is used. E.g. a method Skin::getSearchModule could exist which returns the module name and can be overriden in subclasses as needed.
    • Standard: The Skin class interrface.
    • Benefit: Allow creater control on the skin side (not bound by limitations of a static JSON value), e.g. could take other site configuration into account.
    • Downside: (same)

In the last two cases it is implied that mediawiki.page.ready would use small generated export to know which module to load.

Krinkle removed Krinkle as the assignee of this task.May 25 2020, 5:41 PM
Krinkle added a subscriber: Krinkle.
Niedzielski updated the task description. (Show Details)May 29 2020, 11:50 PM

/cc @Jdlrobson, @nray

@Krinkle, thank you for engaging with this nebulous ticket and helping to define it. This is very helpful and appreciated

The search widget is lazy-loaded upon first interaction currently. I would expect this to remain the case. At that point, it's mainly a matter of how much (if any) technical debt to incurr and/or how many module bundles to create.

Added to task description.

The UniversalLanguageSelector is also loaded on input focus. Here are the requests I see on enwiki:

  • modules=ext.uls.i18n,ime,languagenames,mediawiki,messages|jquery.i18n,ime,uls|jquery.uls.grid|mediawiki.notify (40.2KB)
  • modules=jquery.highlightText,suggestions|mediawiki.searchSuggest (6.8KB)

This is what I understand the requests might look like from your recommendation:

  • modules=ext.uls.i18n,ime,languagenames,mediawiki,messages|jquery.i18n,ime,uls|jquery.uls.grid|mediawiki.notify (40.2KB)
  • modules=vue.runtime|skins.vector.typeaheadSearch (biggg)

The simplest and least compromising approach I see at the moment would be to use skinScripts in mediawiki.page.ready (to change the loading logic), and then have a single module in Vector for the search widget, which would naturally dependen Vue.

(I'm trying to be explicit so I don't misunderstand you.) It's my understanding per T251957#6119332 that packageFiles and skinScripts are incompatible so we either need to use virtual files or change mediawiki.page.ready to use scripts. If we go with virtual files, that change looks something like:

Resources.php
...,
'mediawiki.page.ready' => [
	'localBasePath' => "$IP/resources/src/mediawiki.page.ready",
	'remoteBasePath' => "$wgResourceBasePath/resources/src/mediawiki.page.ready",
	'packageFiles' => [
		'ready.js', // This file is updated to not load anything!
		'checkboxShift.js',
		'checkboxHack.js',
		{
			// This returns a JavaScript file that dynamically loads the existing mediawiki.searchSuggest
			// module or the new skins.vector.typeaheadSearch. That means checking the
			// activeElement / registering the focus listener and calling
			// `mw.loader.load( 'mediawiki.searchSuggest' );` OR
			// `mw.loader.load( 'skins.vector.typeaheadSearch' );`. The default is to load
			// mediawiki.searchSuggest.
			"name": "typeaheadSearchLoader.js",
			"callback": "Hooks::pickTypeaheadSearchLoader"
		}
	],
	'dependencies' => [
		'mediawiki.util',
		'mediawiki.api'
	],
	'targets' => [ 'desktop', 'mobile' ],
	'messages' => [
		'logging-out-notify'
	]
],
...
Vector/skin.json
...
// No changes to this module.
"skins.vector.js": {
	"packageFiles": [
		"resources/skins.vector.js/skin.js",
		"resources/skins.vector.legacy.js/collapsibleTabs.js",
		"resources/skins.vector.legacy.js/vector.js"
	],
	"dependencies": [
		"mediawiki.util",
		"mediawiki.page.ready"
	]
},
// Add new module to Vector.
"skins.vector.typeaheadSearch": {
	"packageFiles": [
		"resources/skins.vector.typeaheadSearch/index.js", // Do whatever we need to do to mount the new Vue.js search component.
		"resources/skins.vector.typeaheadSearch/lib.js" // Some external library for components include the new Vue.js search component.
	],
	"dependencies": [
		"vue.runtime" // A new Vue runtime-only module (T252348).
	]
},
...

Is this understanding correct?

Let skin.json control which module name is used by mediawiki.page.ready. E.g. in skin.json there could be an attribute like SkinSearchModuleName which would default to mediawiki.searchSuggest, but it could be overridden in Vector to skin.vector.search or some such.

I don't think we can do this approach unfortunately. We need this be sensitive to the non-standard "skin version" concept (T237561#5784710). mediawiki.searchSuggest for Legacy (version "1") or Latest (version "2") which differs based on configuration and user preference.

I don't think there's anything left to be done for this task. We have the module to load defined in T257647 and will do so on search input focus just like the old search experience. Please kick back if that's not the case.

Jdlrobson closed this task as Resolved.Aug 10 2020, 8:44 PM
Jdlrobson updated the task description. (Show Details)

agreed