After researching this a bit more, I have found one major difference between map
and path
. I'm not sure if the Magento core team makes deliberate use of this, but per this Stack Overflow answer when you're define a map
configuration, you're actually defining a prefix for mappings. i.e. Not only will this
map: {
'*': {
editTrigger: 'mage/edit-trigger',
}
}
ensure the loading the editTrigger
module actually loads the mage/edit-trigger
module, but also that editTrigger/foo
would load the mage/edit-trigger/foo
module.
The paths
directive is not a prefix mapping. It's a simple one-to-one mapping.
The Magento_Ui/js/lib/ko/initialize
library is, indeed, where Magento initializes its Knockout instance. Magento does not assign a ViewModel when it applies bindings.
The missing key here is the custom KnockoutJS binding named scope
.
When Magento's Knockout instance encounters a scope:
binding like this
<li class="greet welcome" data-bind="scope: 'customer'">
<span data-bind="text: customer().fullname ? $t('Welcome, %1!').replace('%1', customer().fullname) : 'Default welcome msg!'"></span>
</li>
It takes the value of that binding (named customer
), and uses it to load and apply a ViewModel for the inner nodes from the uiRegistry
. You can debug the data bound for a particular scope with some simple KnockoutJS pre
debugging
<div data-bind="scope: 'someScope'">
<pre data-bind="text: ko.toJSON($data, null, 2)"></pre>
</div>
The uiRegistry
is a simple dictionary like object, implemented in the Magento_Ui/js/lib/registry/registry
RequireJS module.
vendor/magento/module-ui/view/base/requirejs-config.js
17: uiRegistry: 'Magento_Ui/js/lib/registry/registry',
Objects are put into the registry via the bits of javascript that look like this
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"customer": {
"component": "Magento_Customer/js/view/customer",
"extra_data_1":"some_value",
"more_extra":"some_other_value",
}
}
}
}
}
</script>
The program in the Magento_Ui/js/core/app
module will examine the components
key of the passed in object, and for each sub-object will
Fetch the object returned by the specified RequireJS
module from the component
key (Magento_Customer/js/view/customer
)
Use that object to instantiate a new javascript object (see below)
Assign any extra data keys to that same object
Add that same object to the uiRegistry
with the key of the original object (customer
above)
If you're not sure how the x-magento-init
script works, I've written an article about it here.
There's a more in depth examination of the app.js
process over in this answer.
The implementation of the scope binding is defined here
vendor/magento//module-ui/view/base/web/js/lib/ko/bind/scope.js
Best Answer
RequireJS has a feature that allows you to set a custom baseUrl.
Magento generates baseUrl for RequireJS in the body of the page, where JS resources are requested. So, it's basically one more part of RequireJS config generated by Magento. This baseUrl is calculated on server side and is based on current theme, locale and base URL for static view files for the store. Then native RequireJS functionality calculates full path as follows