Skip to content

Commit

Permalink
Refactor JavaScript mixins module
Browse files Browse the repository at this point in the history
Fixes #25586.
  • Loading branch information
Mateusz Krzeszowiak committed Nov 16, 2019
1 parent 2cc9d29 commit 540b134
Showing 1 changed file with 57 additions and 95 deletions.
152 changes: 57 additions & 95 deletions lib/web/mage/requirejs/mixins.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,25 @@ define('mixins', [
], function (module) {
'use strict';

var rjsMixins;
var contexts = require.s.contexts,
defContextName = '_',
defContext = contexts[defContextName],
unbundledContext = require.s.newContext('$'),
defaultConfig = defContext.config,
unbundledConfig = {
baseUrl: defaultConfig.baseUrl,
paths: defaultConfig.paths,
shim: defaultConfig.shim,
config: defaultConfig.config,
map: defaultConfig.map
},
rjsMixins;

/**
* Prepare a separate context where modules are not assigned to bundles
* so we are able to get their true path and corresponding mixins.
*/
unbundledContext.configure(unbundledConfig);

/**
* Checks if specified string contains
Expand Down Expand Up @@ -50,14 +68,14 @@ define('mixins', [

/**
* Extracts url (without baseUrl prefix)
* from a modules' name.
* from a module name ignoring the fact that it may be bundled.
*
* @param {String} name - Name, path or alias of a module.
* @param {Object} config - Contexts' configuartion.
* @param {Object} config - Context's configuartion.
* @returns {String}
*/
function getPath(name, config) {
var url = require.toUrl(name);
var url = unbundledContext.require.toUrl(name);

return removeBaseUrl(url, config);
}
Expand All @@ -73,11 +91,11 @@ define('mixins', [
}

/**
* Iterativly calls mixins passing to them
* Iteratively calls mixins passing to them
* current value of a 'target' parameter.
*
* @param {*} target - Value to be modified.
* @param {...Function} mixins
* @param {...Function} mixins - List of mixins to apply.
* @returns {*} Modified 'target' value.
*/
function applyMixins(target) {
Expand All @@ -94,8 +112,13 @@ define('mixins', [

/**
* Loads specified module along with its' mixins.
* This method is called for each module defined with "mixins!" prefix
* in its name that was added by processNames method.
*
* @param {String} name - Module to be loaded.
* @param {Function} req - Local "require" function to use to load other modules.
* @param {Function} onLoad - A function to call with the value for name.
* @param {Object} config - RequireJS configuration object.
*/
load: function (name, req, onLoad, config) {
var path = getPath(name, config),
Expand All @@ -110,14 +133,14 @@ define('mixins', [
/**
* Retrieves list of mixins associated with a specified module.
*
* @param {String} path - Path to the module (without base url).
* @param {String} path - Path to the module (without base URL).
* @returns {Array} An array of paths to mixins.
*/
getMixins: function (path) {
var config = module.config() || {},
mixins;
mixins;

// fix for when urlArgs is set
// Fix for when urlArgs is set.
if (path.indexOf('?') !== -1) {
path = path.substring(0, path.indexOf('?'));
}
Expand All @@ -131,19 +154,19 @@ define('mixins', [
/**
* Checks if specified module has associated with it mixins.
*
* @param {String} path - Path to the module (without base url).
* @param {String} path - Path to the module (without base URL).
* @returns {Boolean}
*/
hasMixins: function (path) {
return this.getMixins(path).length;
},

/**
* Modifies provided names perpending to them
* Modifies provided names prepending to them
* the 'mixins!' plugin prefix if it's necessary.
*
* @param {(Array|String)} names - Module names, paths or aliases.
* @param {Object} context - Current requirejs context.
* @param {Object} context - Current RequireJS context.
* @returns {Array|String}
*/
processNames: function (names, context) {
Expand Down Expand Up @@ -179,101 +202,40 @@ require([
], function (mixins) {
'use strict';

var originalRequire = window.require,
originalDefine = window.define,
contexts = originalRequire.s.contexts,
defContextName = '_',
hasOwn = Object.prototype.hasOwnProperty,
getLastInQueue;

getLastInQueue =
'(function () {' +
'var queue = globalDefQueue,' +
'item = queue[queue.length - 1];' +
'' +
'return item;' +
'})();';

/**
* Returns property of an object if
* it's not defined in it's prototype.
*
* @param {Object} obj - Object whose property should be retrieved.
* @param {String} prop - Name of the property.
* @returns {*} Value of the property or false.
*/
function getOwn(obj, prop) {
return hasOwn.call(obj, prop) && obj[prop];
}

/**
* Overrides global 'require' method adding to it dependencies modfication.
*/
window.require = function (deps, callback, errback, optional) {
var contextName = defContextName,
context,
config;

if (!Array.isArray(deps) && typeof deps !== 'string') {
config = deps;

if (Array.isArray(callback)) {
deps = callback;
callback = errback;
errback = optional;
} else {
deps = [];
}
}

if (config && config.context) {
contextName = config.context;
}

context = getOwn(contexts, contextName);

if (!context) {
context = contexts[contextName] = require.s.newContext(contextName);
}

if (config) {
context.configure(config);
}

deps = mixins.processNames(deps, context);

return context.require(deps, callback, errback);
};
var contexts = require.s.contexts,
defContextName = '_',
defContext = contexts[defContextName],
originalContextRequire = defContext.require,
processNames = mixins.processNames;

/**
* Overrides global 'define' method adding to it dependencies modfication.
* Wrap default context's require function which gets called every time
* module is requested using require call. The upside of this approach
* is that deps parameter is already normalized and guaranteed to be an array.
*/
window.define = function (name, deps, callback) { // eslint-disable-line no-unused-vars
var context = getOwn(contexts, defContextName),
result = originalDefine.apply(this, arguments),
queueItem = require.exec(getLastInQueue),
lastDeps = queueItem && queueItem[1];

if (Array.isArray(lastDeps)) {
queueItem[1] = mixins.processNames(lastDeps, context);
}
defContext.require = function (deps, callback, errback) {
deps = processNames(deps, defContext);

return result;
return originalContextRequire(deps, callback, errback);
};

/**
* Copy properties of original 'require' method.
*/
Object.keys(originalRequire).forEach(function (key) {
require[key] = originalRequire[key];
Object.keys(originalContextRequire).forEach(function (key) {
defContext.require[key] = originalContextRequire[key];
});

/**
* Copy properties of original 'define' method.
* Wrap shift method from context's definitions queue.
* Items are added to the queue when a new module is defined and taken
* from it every time require call happens.
*/
Object.keys(originalDefine).forEach(function (key) {
define[key] = originalDefine[key];
});
defContext.defQueue.shift = function () {
var queueItem = Array.prototype.shift.call(this);

queueItem[1] = processNames(queueItem[1], defContext);

window.requirejs = window.require;
return queueItem;
};
});

0 comments on commit 540b134

Please sign in to comment.