Suppliers

Learn about sharing and reusing values across multiple scripts and views.

Suppliers are scripts which export one or more named values, for the sole purpose of having those values imported by another script โ€” either by another supplier, a JS endpoint, or a Mustache endpoint. Suppliers allow for reusing values and functions. All values exported by suppliers exist in the module '๐Ÿ“ค'.

A general best practice is to keep supplier scripts small and purpose specific. If you're exporting more than a few values out of a single supplier script, then it's likely worth breaking it out into multiple supplier scripts. Keeping supplier scripts small and purpose specific will enhance readability, performance, and maintainability.

Suppliers aren't the only way to share values across many endpoints. Dynamic path parameters will provide model references to all suppliers and endpoints.

Supplier Types

Choosing a supplier type depends on its purpose and allowed values. Supplier files are placed into a sub-directory named '๐Ÿ“ค', and any directory may have a supplier sub-directory. Suppliers are only visible to the current directory where the supplier directory is located, as well as descendant directories. This allows scoping exported supplier values to only those endpoints which need the values/functions.

Request Supplier

๐Ÿ“ค/AnyName.js

Allowed exports: Primitives (String, Number, Boolean), Map/Object of Primitives, a single instance of a Model, or a query.

Only model read/query operations are allowed within the supplier. However the endpoint finally using the supplied value may itself perform write operations if allowed by the endpoint.

Function Supplier

๐Ÿ“ค/{}AnyName.js

Allowed exports: "Utility" functions only. Function Suppliers have very limited functionality. They may not import anything (not even other suppliers). Their primary purpose is to provide functions that perform calculations or transformations on parameters.

HTML Supplier

๐Ÿ“ค/AnyName.html

Allows sharing HTML fragments between server-side JS and Mustache. These suppliers are always represented as functions accepting a single argument exposed as this to the Mustache template.

A good practice for naming these suppliers is ending with either "Fragment", such as ArticleRowFragment.html, or with the name of the primary element ArticleRowDIV.html.

Learn more about using HTML suppliers below.

Export Scope

The path location of a supplier file influences the scope of where its exported values are visible. Only scripts in the same directory, or descendant directories, have access to the exported values of a supplier.

/product/{product}/๐Ÿ“ค/GetLiveProduct.js
import {product} from '๐Ÿ”—';

let liveProduct = product.get();

export {liveProduct as LiveProduct};

The exported value LiveProduct may be imported from the module named '๐Ÿ“ค', for all scripts inside /product/{product}/*, and any descendant directories. For example the Mustache file /product/{product}/related/index.html would be able import the LiveProduct value.

Importing Values

Regardless of where the supplier exists in the path hierarchy, and regardless of the supplier's file name, all supplier values are located in the module named '๐Ÿ“ค'. This creates a simple flat namespace for importing named values.

// Importing specific values:
import {Something, Other, That} from '๐Ÿ“ค';

HTML Suppliers

HTML suppliers are only necessary when sharing a fragment of HTML between both server-side JavaScript and server-side Mustache. It's also useful if multiple Mustache templates need to share an HTML fragment that requires a parameter.

All HTML suppliers are called as a function with a single parameter, even if that single parameter is an empty {}. This parameter is exposed to the HTML supplier as this.

The following example illustrates the definition of the supplier, and accessing the supplier from both environments. The assumption in this example is that /๐Ÿ“ฎnewItem.js is called from a client-side fetch, and the html JSON property is appended to <div class="items">.

/๐Ÿ“ค/ItemDIV.html
<!--TEMPLATE mustache-->
{{#this as item}
<div class="item">
  {{item.name}}
</div>
{{/this}}
/๐Ÿ“ฎnewItem.js
import {Item} from '๐Ÿ“ฆ';
import {ItemDIV} from '๐Ÿ“ค';

let item = new Item().name('ABC');

({id: item.id, html: ItemDIV(item)});
/index.html
<!--TEMPLATE mustache-->
...
{{% import {Item} from '๐Ÿ“ฆ' }}
{{% import {ItemDIV} from '๐Ÿ“ค' }}

<div class="items">
{{#Item.all}}
  {{! triple brackets }}
  {{{ ItemDIV item }}} 
{{/Item.all}}
</div>
...

Endpoint Specific

Endpoint Specific Supplier

Because suppliers follow the hierarchical REST structure, they have varying levels of specificity for an endpoint. The most specific supplier is one with the same name as the endpoint itself. For example, an endpoint named index.html may also have a supplier named ๐Ÿ“ค/index.js. As the most specific supplier, only index.html may access values exported by ๐Ÿ“คindex.js (however index.html may also access other in-scope suppliers).

Pinned Supplier

An extension to an endpoint specific supplier is a "pinned" supplier. Indicate a pinned supplier with the pin emoji, e.g. ๐Ÿ“ค/๐Ÿ“Œindex.js, using the same file name as the target Mustache template. Pinned suppliers may be used to hide or re-expose broader/earlier supplied values.

This is especially useful where more strict separation of concerns are desired, for example in the case of Mustache endpoints. The JavaScript developer may want to ensure that regardless of any suppliers along the REST path, only very explicit / strictly supplied values are visible to the Mustache file.