Giter Site home page Giter Site logo

loopback-boot's Introduction

LoopBack Boot

โš ๏ธ LoopBack 3 has reached end of life. We are no longer accepting pull requests or providing support for community users. The only exception is fixes for critical bugs and security vulnerabilities provided as part of support for IBM API Connect customers. (See Module Long Term Support Policy below.)

We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as soon as possible. Refer to our Migration Guide for more information on how to upgrade.

Overview

A convention-based bootstrapper for LoopBack applications.

For full documentation, see the official StrongLoop documentation: Defining boot scripts and Creating a LoopBack application.

The loopback-boot module initializes (bootstraps) a LoopBack application. Specifically, it:

  • Configures data-sources.
  • Defines custom models
  • Configures models and attaches models to data-sources.
  • Configures application settings
  • Runs additional boot scripts, so you can put custom setup code in multiple small files instead of in the main application file.

For more information, see Defining boot scripts.

Version notes

The version range 1.x is backwards compatible with app.boot provided by LoopBack 1.x versions and the project layout scaffolded by slc lb project up to slc version 2.5.

The version range 2.x supports the new project layout as scaffolded by yo loopback.

This document describes the configuration conventions of the 2.x versions.

Installation

npm install loopback-boot

Usage

var loopback = require('loopback');
var boot = require('loopback-boot');

var app = loopback();
boot(app, __dirname);

app.use(loopback.rest());
app.listen();

See API docs for complete API reference.

Module Long Term Support Policy

This module adopts the Module Long Term Support (LTS) policy, with the following End Of Life (EOL) dates:

Version Status Published EOL
3.x End-of-Life May 2017 Dec 2020
2.x End-of-Life Jul 2014 Apr 2019

Learn more about our LTS plan in docs.

License

This module is provided under dual MIT/StrongLoop license. See LICENSE for details.

loopback-boot's People

Contributors

0candy avatar agnes512 avatar bajtos avatar bitmage avatar candytangnb avatar clarkbw avatar davidcheung avatar dhmlau avatar fabien avatar gunjpan avatar hacksparrow avatar jannyhou avatar johnsoftek avatar kallenboone avatar klarkc avatar kraman avatar nabdelgadir avatar pradnyabaviskar avatar raymondfeng avatar ritch avatar rmg avatar sam-github avatar sequoia avatar shelbys avatar shlomiassaf avatar siddhipai avatar supasate avatar superkhau avatar virkt25 avatar zbarbuto avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loopback-boot's Issues

Using loopback-boot in the browser with browserify

I'm trying to follow the api docs for loopback-boot and docs for running loopback in the browser to get the basic application created with slc lb working, but nothing seems to work.

I'm not sure which appDir I should be pointing to, the server or the client, when running browserify. Also, the models are declared as .json files with the .js files just exporting a function that will take in the model constructor, but other examples for running in the client are exporting a model constructor and requiring it in and manually adding it to the app.model().

My main goal is to be able to use the models created from the configuration in the .json files on both the server and the client, with native JavaScript so I can use it without requiring AngularJS.

Thanks.

Relative paths in `options.bootScripts`

#31 introduced options.bootScripts that can be used to specify additional boot scripts to execute. The script paths are passed directly to require, which means that relative paths are resolved relatively to node_modules/loopback-boot/lib.

We should improve the compiler and resolve any relative paths using appRootDir:

/absolute/path.js -> /absolute/path/.js
module/relative.js -> module/relative.js
./app/relative -> {appRootDir}/app/relative.js

A similar problem in the way how modules, middleware and components are resolved is tracked by #73.

Boot script ordering

The scripts in server/boot are executed by the order of file names as of today.

There are a few use cases that require ordering.

  1. A boot script discovers models from a DB and exposes them as REST APIs. It needs to be executed before the api-explorer.
  2. An async script that needs to be executed after the system-level boot scripts. For example, if we add the following JS file into server/boot today, the express middleware chain will be messed up:

abc.js (this ensures the file name is sorted before rest-api.js, explorer.js)

module.exports = function(app, cb) {
  process.nextTick(cb);
}

In this case, boot(app, __dirname) returns before the rest-api.js is executed. As a consequence, urlNotFound and errHandler come before the rest handler.

// boot scripts mount components like REST API
boot(app, __dirname);

// -- Mount static files here--
// All static middleware should be registered at the end, as all requests
// passing the static middleware are hitting the file system
// Example:
//   var path = require('path');
//   app.use(loopback.static(path.resolve(__dirname, '../client')));

// Requests that get this far won't be handled
// by any middleware. Convert them into a 404 error
// that will be handled later down the chain.
app.use(loopback.urlNotFound());

// The ultimate error handler.
app.use(loopback.errorHandler());

Potential solutions:

  1. Formalize the file names as 01_first.js, 02_second.js for the scaffolded JS files
  2. Use phases (preferred)

In addition, we probably should move the urlNotFound/errorHandler middleware code to a boot script too.

Config merge order

Hello!

As far as I can tell, loopback-boot is merging datasource configs in an order of env -> local -> master, meaning that local config values get clobbered by environment-specific ones. This surprised me, as my understanding from the docs is that local config files are intended to be excluded from VCS and serve as a trump for local setup. I had intended to use this file to tweak a few values in the development environment datasource setup.

Are my expectations off? I would have expected the merge to happen in the order local -> env -> master, meaning that local datasource config trumps environment, with all of them overriding the general config.

`views` dir not found properly

views directory not being set properly with 2.x layout.

For example, in loopback-example-relation, the views directory is inside server/views. If you run slc run inside the server directory, the application works properly. If you run slc run from the project root, it fails because by default, Express looks for views in ./views (but its really in server/views.

After speaking with @sam-github, it was suggested that app.boot() needs to determine the project root given its knowledge of the project layout.

Ideas for v3.0

Copy of comment by @raymondfeng:

  1. I think we need to organize the boot into multiple phases, such as:
    • discover/load: Find and load configurations
    • resolve/wire: Resolve the references (such as model.dataSource) and wire them together
    • startup: Initialize the datasources/models (model class can potentially have lifecycle event listeners)
    • shutdown: Emit events to notify model classes of system shutdown
    • refresh/update: React to config changes, especially additions
  2. How do we load plugin modules, for example, loopback-passport, loopback-push-notification which typically has dependencies to app and also contributes middlewares/models/datasources? See https://github.com/strongloop/loopback-example-component/issues/4
  3. Do we want to support both sync and async booting? Or eager/lazy booting? See #50 for implementation of async boot scripts.

documentation: clarify the use of *.local.js and *.local.json config files

Currently the use of *.local.{js,json} config files are loosely documented within the environment specific configuration page, their intended role is a little unclear though and behavior may produce unexpected results a developer. Inclusion on this documentation page leads you to believe local is an environment (eg NODE_ENV=local, but it's behavior differs from other env specific config files.

From my experience, it seemed that if I had three files config.json, config.local.json and config.development.json if I started my server with NODE_ENV=development the file config.local.json would not factor into the final configuration. This is not the case as config.local.json is always factored.

As the *.local.{js,json} config is always loaded, it is unclear what role it serves compared to the root config. Specifically, if both config.json and config.local.json are always loaded it's unclear why they are both needed.

Consider the following:

config.json

{
   "foo": "bar"
}

config.local.json

{
   "foo": "baz",
   "isLocal": true
}

config.production.json

{
   "foo": "bat"
}

Running the app with NODE_ENV=production produces a merged config which looks like this:

{
   "isLocal": true,
   "foo": "bat"
}

This is applicable to all types of configs loaded using findConfigFiles function.

Related: #93

Export a function to customize config objects

#37 implemented support for merging nested object and array values.

To support more complex scenarios where a simple merge is not enough, we should allow the override file to exports a function(config) and call this function to customize the current configuration.

Warn the user when a config file was not found, but overrides exist

See #71:

A few weeks back I was reading loopback's confluence docs and came across the config page. I saw the alternative config options that loopback supports and I thought: "oh, so I could use a smarter config! Great I need that". so I went ahead, renamed config.json to config.local.js and started converting the code. Substituting json config with a js config was second nature because I've seen it in many projects including my own. I restarted the server and realized the config was not picked up. I went back to the docs page and still couldn't figure it out. It was only after reading the source code that I was able to understand the config requirements. it took a few hours overall as I couldn't immediately spot where configuration is processed.

We should detect such situation and print a warning.

Related: #80.

extend from DataModel

I am trying to integrate loopback-component-passport and extend UserIdentity. But there is an issue

My code is:

models/userIdentity.js

  module.exports = function(userIdentity, UserIdentity) {
    userIdentity.prototype.test = function(duration, cb) {
      cb('test');
    };
  };

and I am getting following error:

AssertionError: Model must be a descendant of loopback.Model

That's caused because userIdentity is DataModel

How can I extend DataModel?

Use filename as the default value for Model name

Use the file name (e.g. product for common/models/product.json) a default value that can be overridden by the name specified in the file.

If we process the file name using _s.capitalize(_s.camelize(name)) where _s is the underscore.string module, both "order-item" and "OrderItem" will produce the same model name "OrderItem".

Declarative definition of model property validations

Loopback/Yo generator creates model with validations property:

{
  "name": "account",
  "options": {
    "mongodb": {
      "table": "account"
    },
  },
  "dataSource": "mongodb",
  "properties": {
    "name": {
      "type": "String"
    },
  },
  "validations": [],
  "relations": {},
  "acls": [],
  "methods": []
}

But I can't find any example or definition of it.

How to use validations?

cannot find module 'instructions.json'

I am creating a bundled angular app. I am using gulp and browserify to bundle the app. browserify has no problem bundling, but when the app loads in the browser, I get
Error: Cannot find module '/app/node_modules/loopback-boot/node_modules/instructions.json'.

The stack error points to https://github.com/strongloop/loopback-boot/blob/master/browser.js#L20.
I have tried a couple of different combinations of the bundling script in https://github.com/strongloop/loopback-example-full-stack/blob/master/client/lbclient/build.js with no success. My next approach will to bundle the loopback client separately from the rest of the app. Any idea why this is not working correctly?

//Gulp bundle function
function browserifyCommon() {
  var config;

  if (watching) {
    config = {
      cache: {},
      debug: true,
      packageCache: {},
      fullPaths: true
    };
  } else {
    config = {};
  }

  var b = browserify(config);

  try {
    boot.compileToBrowserify({
      appRootDir: paths.loopback
    }, b);
  } catch (err) {
    console.log('Loopback failed to bundle', err);
    process.exit(1);
  }

  if (watching) {
    console.log('Watching');
    b = watchify(b);
    b.on('update', function() {
      bundleItUp(b);
    });
  } 

  b.add(paths.appEntry);
  bundleItUp(b);
}

function bundleItUp(b) {
  console.log('Bundling');
  b.bundle()
    .pipe(plumber())
    .pipe(source('bundle.js'))
    .pipe(gulp.dest('/public'));
}
//lbClient.js
var loopback = require('loopback'),
    boot = require('loopback-boot');

var app = loopback();
module.exports = app;
boot(app);
//mainApp.js
require('./app.core');
require('./components');
require('./matView');

require('./loopback'); // Loopback required here! 

// # Main App entry point.
module.exports = angular
  .module('app', [
    'app.core',
    'app.templates',
    'app.mainView'
    //'app.loopback',
  ]);

Environment-specific config: replace the whole config, do not merge

@raymondfeng and @dashby3000 suggested we should change the way how environment-specific configurations are applied.

At the moment, values from datasources.production.json are merged with datasources.json.

The proposal is to drop the merging algorithm and always use only one file. I.e. only load datasources.production.json and completely ignore datasources.json & datasources.local.json when running in production.

The reasoning is that keeping the configuration spread across multiple files makes it more difficult for operations people to quickly see the full configuration that will be applied. It also makes it difficult to switch from host/port/database config to url based config.

Related issues: #82 #4

@rmg @sam-github @ritch @simoami @doublemarked What is your opinion about such change?

Configure datasources via env variables

The Twelve-Factor App recommends to store configuration in environment variables - see the section III. Config.

loopback-boot can already read host and port from environment variables. We should extend this mechanism to cover datasource configuration too.

Proposed naming convention:

DATASOURCE_{ds-name}_{option-name}=VALUE

Example:

DATASOURCE_db_host=staging.mysql.com
DATASOURCE_db_user=webapp

DATASOURCE_email_type=SMTP
DATASOURCE_email_host=smtp.gmail.com

package.json incorrect

loopback-boot currently fails to install through npm, also, the repo url has typos/points to the wrong gh account.

bug: saving instructions to node_modules requires folder with package.json

Ran into an issue after doing an npm install on a project. Not sure what change exactly caused this issue but it's an issue nonetheless (in two separate machines as well).

Was getting this error when bundling (browserify and watchify, with many different versions).

1__tmux

After some digging, changing this line
https://github.com/strongloop/loopback-boot/blob/master/lib/bundler.js#L97

to

var instructionsFile = path.resolve(__dirname, '..', 'instructions.json');

or

var instructionsFile = path.resolve(__dirname, '..', 'node_modules', 'instructions', 'instructions.json');

and adding the file node_modules/instructions/package.json with "main": "instructions" solved the issue.

Will submit PR shortly.

Expected value of app.get('env')

When initializing boot with options, if options.env is supplied, that value does not match what app.get('env') returns.

The env variable is set based on options provided and passed to config loader methods for app, models and datasources. It is never stored beyond the compiler and config loader initialization.

In my opinion it would be beneficial to have app.get('env') match what is supplied in options.env.

Run model configuration after 'attached' (to fix race condition)

Currently I'm unable to perform certain declarations in /models/*.js files, because not all models seem to be attached at that point. The workaround involves wrapping the code in a on('attached', function() { ... }) wrapper. I think this should be the default e.g. to run all 'model configurator' scripts after all models have been defined/attached.

Expose API for custom ConfigLoader

It would be great for loopback-component-passport to load its providers.json via the same method as the rest of the config in loopback, i.e. from providers.local.js and providers.ENV.js.

I've implemented this manually using lodash's merge function, but would be great to reuse the code from ConfigLoader.

Allow model logic code from compiled function

At the moment, application logic for models is defined in static module files.
The executor loads the module in the process of defining a model.

This is the only way when models are defined using 'model-config.js`

Issue #49 suggests custom model definition loading.
PR #96 implements #49 using additional property that holds model definition objects instead of them being in modelDir/modelName.json. An additional property is used to define the sourceFile (logic) for each model.

This approach forces external packages to supply a path to a file that holds the model logic.

When using dynamic model-config one can use a file to hold the model logic, as used today AND can also hold the logic in a pre-loaded function/module/etc...

The 2nd approach is not supported and it is quite simple to support it simple by checking if 'sourceFile' is a string or a function and acting accordingly.

This improves control by many factors...

Model logic loading section, HERE

NOTE: If choosing to implement via the same parameter (sourceFile), make sure to change logic in complier so path verification is ignored if parameter is a function.

NOTE-2: This suggestion has no dependency with #49 or #96 since custom model-config is already supported, only custom model definition is not.

AssertionError: undefined == true

Can not start node app , occur this error

assert.js:86
throw new assert.AssertionError({
^
AssertionError: undefined == true
at /home/ken/api/node_modules/loopback/lib/model.js:392:7
at EventEmitter. (/home/ken/api/node_modules/loopback/lib/model.js:222:9)
at EventEmitter.g (events.js:199:16)
at EventEmitter.emit (events.js:129:20)
at EventEmitter.app.model (/home/ken/api/node_modules/loopback/lib/application.js:157:9)
at /home/ken/api/node_modules/loopback-boot/lib/executor.js:171:9
at Array.forEach (native)
at setupModels (/home/ken/api/node_modules/loopback-boot/lib/executor.js:167:23)
at execute (/home/ken/api/node_modules/loopback-boot/lib/executor.js:32:3)
at bootLoopBackApp (/home/ken/api/node_modules/loopback-boot/index.js:129:3)

Multiple invocation of the same boot script

#31 introduced options.bootScripts that can be used to specify additional boot scripts to execute. The implementation uses a simple concat-based algorithm to build a list of all scripts to execute. As a result, it's possible to get the same boot script (exported function) executed twice.

Consider the following example:

// boot/step.js
console.log('step loaded');
module.exports = function(app) {
  console.log('step executed');
};

// app.js
boot(app, {
  appRootDir: __dirname,
  bootScripts: [ path.resolve(__dirname), 'boot', 'step.js' ]
});

Actual output:

step loaded
step executed
step executed

Expected output:

step loaded
step executed

Dynamic config options

It turns out that per-environment dynamic overrides via config.{env}.js are not good enough, as many users prefer to keep all config in a single javascript file (see e.g. #71). The current solution is to use config.local.js for that, even thought that file was initially intended for machine-local configuration that should not be checked into VCS (git, svn).

I am proposing to:

  • Add a new suffix similar to local, files with this suffix will be always loaded. Possible suffixes: dynamic, all. This new suffix should be supported at least by datasources.json, config.json and middleware.json.
  • Update the documentation and explain the difference between the new suffix and local, describe when to use which one.
  • Add new unit tests to loopback-workspace to ensure it can handle missing config.json file. Possibly also change the implementation so that it does not create an empty config.json file.
  • Make the file config.json (and only this file) optional.

npm test fails with node 0.10.x, but passes with 0.11.x.

Int32Array is used by sha.js, which is used by browserify for Node crypt module.

See https://github.com/dominictarr/sha.js/blob/master/sha1.js#L24

1) browser support has API for bundling and executing boot instructions:
     Uncaught ReferenceError: Int32Array is not defined
      at module.exports (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:3254:15)
      at Object.require../hash (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:3227:33)
      at s (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:1:228)
      at /Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:1:279
      at Object.<anonymous> (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:2577:18)
      at Object.require../md5 (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:2608:4)
      at s (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:1:228)
      at /Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:1:279
      at Object.<anonymous> (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:2705:22)
      at Object.require../create-hash (/Users/rfeng/Projects/loopback/loopback-boot/test/sandbox/browser-app-bundle.js:2749:4)

Support nested values in config overrides

At the moment, loopback-boot does not support non-value types like arrays or objects in .local.json and .js config files.

The reason for that is with non-value types, there are multiple possible operations that one may want to perform:

  1. override the whole value, replace one object/array with another
  2. override the item at a given index in an array or replace the value of the given key in an object
  3. add items to an array or key/values to an object
  4. remove items from an array or delete key/values from an object

We should come up with a solution flexible enough to support most of these use-cases. Note that they are recursive, e.g. one may want to override the object value of the ssl key in object stored under the transport key.

Declaratively load loopback.rest and loopback-explorer

In order to remove boot/rest and boot/explorer from the api-server template, we need to extend loopback-boot to support the following features:

  1. Specifying middleware parameters as a value to be read via app.get from config.json, example:

    {
      "routes": {
        "loopback#rest": {
          "paths": ["${restApiRoot}"]
        }
    }
  2. Allowing the middleware to be optional, e.g.

    {
      "routes": {
        "loopback-explorer": {
          "optional": "Run `npm install loopback-explorer` to enable the LoopBack explorer.",
          "params": {
            "basePath": "$!{restApiRoot}"
          }
       }
    }
  3. Rework the explorer so that it can get the app object via req.app on the first request, in the same way as loopback.rest.

Asynchronous initialisation process

Due to the current implementation of the boot process using this invocation style:

javascript
module.exports = function someBootScript(app) {
  // Init models, ...
  // Setup relationships
  // Other async stuff
};

it is currently not really possible (in a clean way) to have loopback wait with accepting requests until complete finalisation of the boot process. Some asynchronous operations may not yet have finished.

Please adjust this to something like:

module.exports = function someAsyncBootScript(app, done) {
  // Init models, ...
  // Setup relationships
  // Other async stuff that calls done() when ready.
};

And only start the listener after this... It should be fairly easy to implement this using Q.all()...

Command line browserify loopback-boot

We compile on npm prepublish for production. When trying to browserify the loopback script we have does not get run.

Not exactly sure how to add boot instructions from command line. I would form a PR but this isn't something I am familiar with.

Is there someway to easily accomplish this?

Add support for declarative policies

To support declarative gateway configurations, we need to add support to loopback-boot to deal with policies.json and transcompile it into middleware.json.

Extend options arg to support custom model definitions

Extend the options argument of boot/compile to allow the developer to supply custom model definitions (to replace the result of findModelDefinitions). Together with the existing options.models, it will allow you to specify all model-related data and still use the benefits which loopback-boot provides (most notably loading models in order defined by inheritance, i.e. base models are loaded before models that are extending them).

boot(app, {
  models: {
    Car: { dataSource: 'db' },
    // etc.
  },
  modelDefinitions: [
     {
       definition: {
         name: 'Car',
         properties: { /*...*/ }
       },
       sourceFile: 'path/to/car.js'
    },
    // etc.
  ]
});

This is a follow-up for #27.

Shorthand notation for middleware paths in `middleware.json`

This is a follow-up for #66.

Can we hide the structure of the component somehow by handling this a bit differently:

loopback/server/middleware/rest

I don't really care what the reference is as long as "server/middleware" isn't repeated in all middleware.json files.

Cannot boot two browserified apps

var instructions = require('loopback-boot#instructions');

Uses a single global name to reference the instructions. You should be able to specify this in boot.compileToBrowserify() and boot() as a param.

I should be able to do something like:

// in your pre-boot / build script
boot.compileToBrowserify({
  id: '...your app identifier...',
  ...
}, b);


// in your runtime / boot phase
boot(..., {id: '...your app identifier...'})

Mixins

LoopBack provides two kinds of mixins which we need to support in loopback-boot too:

  • A regular LoopBack model - mixing process copies all properties and methods to the target model.
  • A function - mixing process calls the function after the model has been attached.

Mixin as a model - NOT IMPLEMENTED

loopback-boot already has mechanism for defining arbitrary models, we should reuse this mechanism for defining mixins too. Benefits: developers can apply their knowledge about how to create models to create mixins too. Tools like yo loopback:model and Studio will support mixin definitions OOTB.

// common/models/timestamp-mixin.json
{
  "name": "TimeStampMixin",
  "properties": {
    "timestamp": "Date"
  }
}

// common/models/timestamp-mixin.js
module.exports = function(TimeStampMixin) {
  // setup auto-update of timestamp on save
}

To support this kind of mixins, we need to extend addAllBaseModels() and sortByInheritance() to take into account mixed-in models in addition to base models. Once that is done, model-like mixins will work both on the server and in the browserified client.

Note that this is can be implemented independently (and should be).

Mixin as a function

This is the part where we need to come up with a new convention.

Ultimately, I'd like to see a solution similar to what we have for models, where the compiler understands relations between model definitions and mixin definitions, and can build optimised instructions to load only those mixins that are actually used in the app.

Another thing to consider is the new component architecture as outlined here.

I am trying to come up with a small solution that can be incrementally extended in next PRs.

How about this:

  • compiler takes two new options: mixinScripts that contains a list of source files to load, normalizeNames that defines the algorithm for converting file names into mixin/model names.
  • mixin names are built from file names by the compiler, using normalizeNames
  • executor is extended to define mixins per instructions from the compiler

Usage:

boot(app, {
  appRootDir: __dirname,
  mixins: [ './mixins/timestamp.js' ]
});

The next step is to implement clever auto-loading of mixins from directories, as described earlier. That way the usage would become

// explicit
boot(app, {
  appRootDir: __dirname,
  mixinSources: [ './mixins' ]
});

// relying on the default mixinSources value
boot(app, __dirname)

To summarise the next steps as I see them now:

  1. Support mixins defined as models
  2. Support mixins defined as functions via mixins option
  3. Support mixins defined as functions via mixinSources option

Random notes:

  • It seems to me that the setup is not handled correctly by the current mixing architecture. Imagine a TimeStampMixin as outlined above that adds a setup method to configure hooks to update the timestamp. Such setup method would override any setup method provided by the target class. This is most likely a problem of Model hooks in general as the same applies to beforeSave.
  • How can a Model that is being mixed in access the mixin options provided by the app? It seems to me these options are discarded when the mixin is a Model instead of a function.

This issue is a follow-up for the unfinished pull request #33, the discussion there contains useful bits of information too.

Compiler Glob Style File lookups

It would be much cleaner and easier to maintain from a project standpoint, if the compiler could use glob patterns to locate files over hard coded paths and private filter functions.

rather than instead of

"../common/models",
"../server/models",
"./models",
"../../../project/auth/models",
"../../../project/products/models"

it can just be

"node_modules/loopback/**/models/*.+(js|json)",
"../../../project/pluggables/**/models/*.+(js|json)"

This would reduce the amount of hand managed configuration. It also makes it easier to support pluggable pieces by convention in one's application.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.