Component metadata is stored in package.json
under loopback-component
property.
// package.json
{
"loopback-component": {
"facets": {
"server": {
"dependencies": [
// a dependency specific to this facet only
"./common"
],
"settings": {
// LDL description of config options
}
},
"common": {
"dependencies": [
],
"settings": {
// LDL description of config options
}
},
}
"dependencies": [
// a shortcut version for declaring a dependency used by all facets
// server facet depends on loopback-component-push/server,
// common facet depends on loopback-component-push/common,
// etc.
"loopback-component-push"
]
}
}
This has a nice side-effect that the workspace does not need to scan the
filesystem to find what facets the project contains - all metadata is stored
in package.json
.
// server/index.js
module.exports = function(app, options, next) {
// mount an express middleware
app.use(compress());
// add a route
app.get('/login', login);
// produce an event
app.emit('strawman', this);
next();
}
// server/datasources.json
{
"push": {
"connector": "../connector", // facet-relative path
// etc."
}
}
Note: all datasources are exported, it is not possible to create a facet-private datasource.
loopback-boot should load datasources provided by all dependencies listed
in app's facet.json
(recursively).
// server/models/foo.json
{
"name": "Foo",
"properties": {
// etc.
},
// etc.
}
Note: all models are exported, loopback-boot will load only the models that are configured by the app.
For each dependency listed in app's facet.json
(recursively),
loopback-boot should add {facet}/models
to the directories scanned for model
definitions.
Since connectors are resolved through require, components should provide
a standalone file for each connector. E.g. loopback-component-push/connector
.
To allow components to use their connectors in datasources.json
, loopback
should resolve relative paths in connector names before calling require
.
To use component, one has to:
npm install
the package- add component facets as dependencies of app facets
- provide facet configuration
This uses the same mechanism as described in "Component definition" above.
Many components require a user-provided configuration, e.g. the push component requires auth credentials for APNS and GCM.
The configuration must be dynamic, i.e. the developer should be able to specify different values for development and production and also compute the values using arbitrary javascript code.
Since facets can depend on another facets, there should be a way how to forward/transform the configuration provided by the app to the facets that are dependencies of app facets.
// in the app project
// server/facet-config.json
// (merged with server/facet-config.production.*, etc.)
{
"loopback-component-push/server": {
"gcm": { "key": " ..." },
"job-queue-name": "foobar-push-notifications",
// etc.
}
}
// in the component
// node_modules/loopback-component-push/server/configure.js
// @param facetConfig the initial configuration provided by facet-config.json
// @param settings settings object provided by the app
// @param next callback
module.exports = function(facetConfig, settings, next) {
// configure loopback-component-job-dispatcher that we are depending on
facetConfig['loopback-component-job-dispatcher'] = {
// use the value provided in our settings
'queue-name': 'loopback push' || settings['job-queue-name']
};
}
We can support configure.js
in top-level applications too, in which
case the settings
object can be the configuration provided by config.json
.
Drawbacks: facet configuration is coupled with the configuration of depending component facets (i.e. the config code has to know which components/facets are listed as dependencies), but the configuration lives in a different file.