Reduce bundlesize of reference previews by making it use stable APIs

This is a precursor to moving the code out to the Cite extension.

This can be squashed into parent commit or merged at same time.

I've kept the two patches separate to make them easier to review.

Bug: T326692
Change-Id: I50dbf28a1078df6c73fd0fbf77480488dd82c7b3
This commit is contained in:
Jon Robson 2024-01-12 12:08:54 -08:00 committed by WMDE-Fisch
parent 59c6b8e88f
commit 381f8f5f7d
13 changed files with 49 additions and 40 deletions

View file

@ -153,6 +153,9 @@
]
},
"ext.popups.referencePreviews": {
"dependencies": [
"ext.popups.main"
],
"styles": [
"resources/ext.popups.referencePreviews/referencePreview.less"
],

View file

@ -75,7 +75,7 @@
},
{
"path": "resources/dist/referencePreviews.js",
"maxSize": "2.7kB"
"maxSize": "2.0kB"
}
]
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -3,7 +3,6 @@
*/
import { TYPE_REFERENCE } from './constants.js';
import { abortablePromise } from '../gateway/index.js';
/**
* @return {Gateway}
@ -83,7 +82,10 @@ export default function createReferenceGateway() {
sourceElementId: el.parentNode.id
};
return abortablePromise( Promise.resolve( model ) );
// Make promise abortable.
const promise = Promise.resolve( model );
promise.abort = () => {};
return promise;
}
return {

View file

@ -2,24 +2,25 @@
* @module referencePreview
*/
import { isTrackingEnabled, LOGGING_SCHEMA } from './referencePreviews';
import { renderPopup } from '../ui/templates/popup/popup';
import { createNodeFromTemplate, escapeHTML } from '../ui/templates/templateUtil';
const templateHTML = `
<div class="mwe-popups-container">
<div class="mwe-popups-extract">
<div class="mwe-popups-scroll">
<strong class="mwe-popups-title">
<span class="popups-icon"></span>
<span class="mwe-popups-title-placeholder"></span>
</strong>
<bdi><div class="mw-parser-output"></div></bdi>
</div>
<div class="mwe-popups-fade"></div>
</div>
<footer>
<div class="mwe-popups-settings"></div>
</footer>
const TEMPLATE = document.createElement( 'template' );
TEMPLATE.innerHTML = `
<div class="mwe-popups mwe-popups mwe-popups-type-reference" aria-hidden>
<div class="mwe-popups-container">
<div class="mwe-popups-extract">
<div class="mwe-popups-scroll">
<strong class="mwe-popups-title">
<span class="popups-icon"></span>
<span class="mwe-popups-title-placeholder"></span>
</strong>
<bdi><div class="mw-parser-output"></div></bdi>
</div>
<div class="mwe-popups-fade"></div>
</div>
<footer>
<div class="mwe-popups-settings"></div>
</footer>
</div>
</div>`;
/**
@ -54,8 +55,12 @@ function renderReferencePreview(
titleMsg = mw.message( 'popups-refpreview-reference' );
}
const el = renderPopup( model.type, createNodeFromTemplate( templateHTML ) );
replaceWith( el.querySelector( '.mwe-popups-title-placeholder' ), escapeHTML( titleMsg.text() ) );
const el = TEMPLATE.content.cloneNode( true ).children[ 0 ];
replaceWith(
el.querySelector( '.mwe-popups-title-placeholder' ),
mw.html.escape( titleMsg.text() )
);
// The following classes are used here:
// * popups-icon--reference-generic
// * popups-icon--reference-book

View file

@ -3,12 +3,10 @@ import { initReferencePreviewsInstrumentation } from './referencePreviews';
import createReferenceGateway from './createReferenceGateway';
import renderFn from './createReferencePreview';
import { TYPE_REFERENCE, FETCH_DELAY_REFERENCE_TYPE } from './constants';
import createUserSettings from '../userSettings';
import setUserConfigFlags from './setUserConfigFlags';
setUserConfigFlags( mw.config );
const userSettings = createUserSettings( mw.storage );
const referencePreviewsState = isReferencePreviewsEnabled( mw.user, userSettings, mw.config );
const referencePreviewsState = isReferencePreviewsEnabled( mw.user, mw.popups.isEnabled, mw.config );
const gateway = createReferenceGateway();
window.refPreviews = referencePreviewsState !== null ? {

View file

@ -3,19 +3,18 @@ import { TYPE_REFERENCE } from './constants.js';
/**
* @module isReferencePreviewsEnabled
*/
const canSaveToUserPreferences = require( '../canSaveToUserPreferences.js' );
/**
* Given the global state of the application, creates a function that gets
* whether or not the user should have Reference Previews enabled.
*
* @param {mw.User} user The `mw.user` singleton instance
* @param {Object} userSettings An object returned by `userSettings.js`
* @param {Function} isPreviewTypeEnabled check whether preview has been disabled or enabled.
* @param {mw.Map} config
*
* @return {boolean|null} Null when there is no way the popup type can be enabled at run-time.
*/
export default function isReferencePreviewsEnabled( user, userSettings, config ) {
export default function isReferencePreviewsEnabled( user, isPreviewTypeEnabled, config ) {
// TODO: This and the final `mw.user.options` check are currently redundant. Only this here
// should be removed when the wgPopupsReferencePreviews feature flag is not needed any more.
if ( !config.get( 'wgPopupsReferencePreviews' ) ) {
@ -31,10 +30,8 @@ export default function isReferencePreviewsEnabled( user, userSettings, config )
return null;
}
// For anonymous users, the code loads always, but the feature can be toggled at run-time via
// local storage.
if ( !canSaveToUserPreferences( user ) ) {
return userSettings.isPreviewTypeEnabled( TYPE_REFERENCE );
if ( user.isAnon() ) {
return isPreviewTypeEnabled( TYPE_REFERENCE );
}
// Registered users never can enable popup types at run-time.

View file

@ -21,6 +21,8 @@
*/
/**
* @stable this function is available to 3rd parties. Any breaking changes must
* go through the MediaWiki deprecation process.
* @param {Promise|jQuery.Promise<T>} promise
* @param {function(): void} [abort]
* @return {AbortPromise}

View file

@ -30,10 +30,11 @@ export default function createMwPopups( store, registerModel, registerPreviewUI,
) {
return {
/**
* @param {string} [type] type of preview, defaults to page if not provided.
* @return {boolean} If Page Previews are currently active
*/
isEnabled: function isEnabled() {
return !!store.getState().preview.enabled[ previewTypes.TYPE_PAGE ];
isEnabled: function isEnabled( type ) {
return !!store.getState().preview.enabled[ type || previewTypes.TYPE_PAGE ];
},
/**
* @stable Do not remove properties in the type PopupModule without providing backwards

View file

@ -125,23 +125,24 @@ QUnit.test( 'all relevant combinations of flags', ( assert ) => {
get: () => {}
}
},
userSettings = {
isPreviewTypeEnabled: () => data.isAnon ?
data.enabledByAnon :
assert.true( false, 'not expected to be called' )
isPreviewTypeEnabled = () => {
if ( !data.isAnon ) {
assert.true( false, 'not expected to be called' );
}
return data.enabledByAnon;
},
config = {
get: ( key ) => key === 'skin' && data.isMobile ? 'minerva' : data[ key ]
};
if ( data.isAnon ) {
user.options.get = () => assert.true( false, 'not expected to be called' );
user.options.get = () => assert.true( false, 'not expected to be called 2' );
} else {
user.options.get = () => data.enabledByRegistered ? '1' : '0';
}
assert.strictEqual(
isReferencePreviewsEnabled( user, userSettings, config ),
isReferencePreviewsEnabled( user, isPreviewTypeEnabled, config ),
data.expected,
data.testCase
);