Skip to content

Rapid development framework for Single Page Applications based on MEAN stack. Inspired by Django.

License

Notifications You must be signed in to change notification settings

alonbardavid/moonshine

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

moonshine

Moonshine is a web framework for rapid development for SPA (Single Page Application) websites built with the MEAN stack - Mongodb, express.js, angular.js and node.js, inspired by Python's Django framework.

The main purpose behind Moonshine is to create a framework that allows you to create reusable components providing both server-side and client-side functionality in a SPA application.

WARNING!!! Moonshine is in very early Alpha, and should be used with great care.

For those who prefer examples, you can check out the examples repository

###Features (Core):

  • A component framework and ecosystem that lets you build modules that interact with other modules by using and providing extensions, which you can share with others.
    • For example consider a Scheduled Job component - that allows other modules to have files that define what jobs to run and at what times. Components can also send events which can be registered on a shared event-emitter.
  • Dependency resolution mechanism that allows you to run functions by dependency order, and makes sure components are initialized before being used.
  • A service locator pattern (directly accessible from the moonshine module).
  • A command framework that allows you to design commands as part of you Component which you can run on the command line (and initializes all relevant components).
  • A configuration system that allows Components to override configuration provided by Components they depend on.

###Features (bundled):

  • Standard based logging.
  • Bundled test commands - for Mocha and Karma.
  • Easy access to the main express.js app
  • Static file management - Components can now expose both server-side and client-side code.
  • Persistence with Mongodb - easy placement of Model files, Components can define and register their own models
  • Rest interface for you Mongodb models - Components can register routes for commonly used models.

##User guide:

###Table of content

###Installation:

To install:

npm install moonshine-js

Make sure you have a mongodb service running on the default port.

To run moonshine commands globally:

npm install moonshine-cli -g

###Quick start: Let's make a simple example of a note application (you'll be able to add notes, and they'll persist to the database, refresh to see them appear). Create an empty file called index.js (moonshine.js requires one at the moment) Create a file in your project folder called "model.js" with the following:

	var Note = require("moonshine-js").db.getSchema("Note");
	Note.add({
		text: String,
	})

Create a file called "api.js" with the following:

	require("moonshine-js").api.createResource("Note")

Create a file called "static/index.html" (index.html file inside a folder named "static"), with the following:

	<html ng-app="exampleApp">
		<head>
		<script src="lib/angular.js"></script>
		<script src="lib/underscore-min.js"></script>
		<script src="lib/restangular.min.js"></script>
		<script src="js/moon.angular.js"></script>
		<script type="text/javascript">
			var example =angular.module('exampleApp',["moon.angular"])
			example.controller("MainCtrl",["Restangular","$scope",function(Restangular,$scope){
				var resource = Restangular.all('notes')
				resource.getList().then(function(notes){
					$scope.notes = notes;
				});
				$scope.addNote = function(newNote) {
					resource.post(newNote).then(function(newResource){
							$scope.notes.push(newResource);
					})
				}	
			}])
		</script>
		</head>
		<body>
		<div ng-controller="MainCtrl">
			<div>notes:</div>
			<div ng-repeat="note in notes">
				{{note.text}}
			</div>
			<div> add new note:</div>
			<div><label>text:</label><input type="text" ng-model="newNote.text"/></div>
			<button type="submit" ng-click="addNote(newNote);newNote={}">Submit</button>
		</div>
		</body>
	</html>

now just type moonshine runserver and go to http://localhost:8080/ to see the result.

###Using components: Create a settings.js file, and add the component to module.exports.requiredComponents (requiredComponents is a list of modules that can be resolved using require.resolve).

For instance to use moon-contrib-user simply add the following line to your settings.js file:

	module.exports.requiredComponents = ["moon-contrib-user"]

Note that you can also use local components (for instance "./my-component")

###Creating extendable components: All applications built with moonshine are essentially Components. However to enable reusability and cross interaction, moonshine provides Components with extension points that allow for easy integration with other Components.

  • extension.js - If a Component has an extension.js file in it's source folder, moonshine will incorporate it in it's extension lifecycle. An extension.js file can expose certain attributes in it's export object that moonshine will run:
    1. setup(done) - this function is called once for every extension in dependency order.

    2. extend - an object container three functions: 2.1. before(done) - called before the process phase begins.

      2.2. process(component,done) - is called for each component in dependency order.

      The component variable is the actual index module of the component (not it's export), so you can use it's resolve and require functions. Note that moonshine calls each extension with all components in order. For example, if we have comp1,comp2 components and ext1,ext2 components the order of execution will be: ext1.process(comp1),ext1.process(comp2),ext2.process(comp1),ext2.process(comp2)

      2.3. after(done) - called after all components have been processed in the process phase.

  1. wrapup(done) - this function is called once for evey extension in dependency order after all extend phases have been completed.
  • signals

    Moonshine exposes a unified event system - require("moonshine-js").signal(signalName,params) . Any module can listen on it by using require("moonshine-js").addHook(signalName,function())

  • commands

    Moonshine allows you to create arbitrary commands that can be run using the moonshine cli. To create a command inside you component, add a commands folder inside your source folder. Any javascript file in it that exports an execute command will be accessible using that file's name (I.E. if it's named test.js, you can use moonshine test in the terminal to run it) The command will be run after all other components have been loaded, so you have access to the full power of Moonshine.

  • settings Moonshine has a configuration object that is available under require("moonshine-js").settings. Any Component can had to that object by including settings.js file inside it's source folder. settings.js file needs to export a config method that receives a settings object (I.E. exports.config = function(settings){ settings.MY_SETTING = false;} )

    You can also override settings for Component that you depend on, and Component that depend on your Component can override your settings.

  • register service Moonshine provides a rudimantery Service locator interface, simply call require("moonshine-js").registerService(yourService), and anyone can access your service using require("moonshine-js").yourService .

##Bundled features ###Mongodb support: Moonshine comes built in with support for mongodb using Mongoose. Any Component can add a model.js file (or model folder with index.js file) that will be called during the Model registration phase. You can use moonshine.db.getSchema() to retrieve (or create a new) Mongoose Schema . Moonshine will automatically register the schemas as models and connect to the database after all models are loaded.

API

  • Extension files:

    • model.js: where you should define your Schemas.
  • Service:

    • moonshine.db:
      • models: a map of models after they have been registered in Mongoose
      • schemas: a map of the original schemas
      • getSchema: a function to retrieve a Schema or create a new Schema.
      • Schema: access to Mongoose's Schema object
      • native: the native Mongoose object
  • Signals:

    • db.models_loaded: called after all models have been registered with Mongoose.
    • db.connected: called after moonshine connected to the database
  • Available Settings:

    • DB_CONNECTION: connection string for the mongodb service. -- defaults to mongodb://localhost/moonshine

###Express.js support: Moonshine exposes the express.js app via moonshine.server.app , which is available to define new routes or register middleware.

API

  • Service:

  • moonshine.server:

    • app: the express.js app
    • native: access to the express.js object
    • httpServer: available after the runserver command completes, exposes the node.js' http.createServer object
    • shutdown: function receiving callback. Available after the runserver command completes successfully, will shutdown the server
  • Signals:

  • server.started: called after runserver command completes successfully

  • server.shutdown: called after the httpserver was closed successfully

  • Available Settings:

  • SERVER_PORT: the port to listen on. Defaults to 8080

  • Commands:

  • runserver: starts the server.

  • test: if mocha is installed, will run all test/**/*.spec.js files from the current working directory.

###Logging support: Moonshine provides a centralized logging framework available under moonshine.logFactory. Use require("moonshine-js").logFactory() to create a new logger, which automatically uses the module's filename in logs.

API

  • Service:

  • moonshine.logFactory: a function that will return a logger.

  • logging:

    • __native: access to the native winston object.
  • Available Settings:

  • LOGGING_ROOT_PATH: defaults to the cwd. When logging filenames of callers, it will reduct the LOGGING_ROOT_PATH from the filename, for shorter logs

  • LOGGING_WINSTON_COLOR: winston colors object.

  • LOGGING_LOG_LEVEL: what level to log. defaults to "debug"

  • LOGGING_SETUP_TRANSPORTS: a function that receives the winston object and can define different transports. The default transport is the console.

###Static file support: Moonshine allows all components to define a "static" folder inside their source folder, that will be exposed to clients. Anything under the static folder will be available to routes. Components can override static files of Components they depend on.

API

  • Extension files:

  • static: any files under Static folder will be available under the static_routes path.

  • Service:

  • static:

    • files: a map of routes mapped to absolute file paths.
  • Available Settings:

  • STATIC_ROUTES: a map of routes and filesystem prefixes. --defaults to "/":"/".

    For example in the default case the file "static/myFile.html" will be available under localhost:port/myFile.html In the case of "/first":"/prime", the file "static/prime/myFile.html" will be available under localhost:port/first/myFile.html

  • STATIC_ALIAS: a map of aliases for routes. defaults to "/":"/index.html"

###Baucis support: Moonshine provides easy REST services using Baucis. Any Component can add an api.js file (or an api folder with index.js file) that will be called during the Api registration phase. You can use moonshine.api.createResource(name,options) to create a new resource using Baucis. Moonshine will automatically register the apis after all apis are loaded.

API

  • Extension files:

  • api.js: where you should define your Resources.

  • Service:

  • moonshine.api:

    • resources: a map of resources after they have been registered with Baucis
    • resourceOptions: a map of the original options sent to Baucis
    • createResource(singular name,options): a function to create a new Resource.
    • createNestedResource(singular name, parent resource name,options): a function to create a resource that will be nested under the parent resource.
    • native: the native Baucis object
  • Signals:

  • api.resources_loaded: called after all resources have been loaded.

  • api.api_registered: called after the Baucis object was added to express.js

  • Available Settings:

  • API_ROOT_PATH: url prefix for accessing the api. defaults to "/api/v1/"

###Angular.js support: Angular.js,Restangular and angular-ui-router libraries are available under "/lib" static route. A new angular module called moon.angular is available under moon.angular.js, which fixes some Restangular defaults to match Moonshine's workbase. It also provides a way to load modules on the fly using the scriptLoader module.

API

  • Angular modules:
  • moon.angular: performs defaults configurations for Restangular.
  • Services:
  • scriptLoader: the angular.js file provided with moonshine was patched to include angular/angular.js#4694. When changing routes, the scriptLoader will attempt to fetch a module by the name of the route (I.E. if the route was "temp", it'll attempt to find "/js/temp.js".
  • scriptLoaderProvider:
    • scriptPrefix: change script prefix path. defaults to "/js"
    • disableAutoScriptLoading: prevent automatic script loading on route change. defaults to false
    • scriptLocationResolver(stateInfo): a function that allows arbitrary path resolution.

###Testing Moonshine comes with two built in testing support - Mocha and Karma .

  • Mocha : if you have Mocha installed in node_modules, and run moonshine test all files under the pattern test/**/*.spec.js will be run using Mocha.
  • Karma : if you have Karma and karma-mocha installed in node_modules, and run moonshine test all files under the pattern test/**/*.client.js will be run using Mocha.
  • you can add a karma.config.js file in your cwd to override default karma config (to use a different test runner or browser for instance)
  • moonshine automatically adds Angular.js files and any js file under the static folder to the list of served karma files.
  • you can add testing libraries to test/client/*.js and they'll be added as well (for instance if you want to add expect.js or angular mocks, etc...)

###Gotchayas:

  • Always add Components to the peerDependencies section of you package.json
  • You need to define Component dependencies in settings.js module.exports.requiredComponents as well as in package.json

Featured Components:

Libraries/Frameworks used:

Philosophy:

  • Little magic, no generators - explicit is better than implicit (but always use reasonable defaults).
  • Lightweight and Modular- components do only one thing, depend on as few components as possible and provide extensions points to allow other modules to integrate with it.
  • Best of breed - make using the most used projects/libraries/frameworks together easier.

License MIT: http://opensource.org/licenses/MIT

About

Rapid development framework for Single Page Applications based on MEAN stack. Inspired by Django.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published