Code Monkey home page Code Monkey logo

aura's Introduction

Aura 0.9.4

NPM version Build Status

Aura is an event-driven architecture for developing scalable applications using reusable components. It works great with Backbone.js, but is framework-agnostic, adapts many best-practice patterns for developing maintainable apps and has first-class support for modern tools like Bower, Grunt and Yeoman.

Aura has been used to develop applications like MIT's Reap and is currently under active development.

Project updates

January, 2015

At this time, we are aware that a number of developers are using Aura in production and welcome help with improving the core codebase via patches, feedback or improvements to our documentation. We have not yet had time to refactor the codebase into a set of Web Components (per the last periodic update), but are still interested in doing this.

If you are interested in taking over core maintenance of the project please feel free to get in touch.

December, 2013

We first started AuraJS two years ago and have evolved it over time (with the help of engineers at Hull.io and our contributors) to meet the needs of the RequireJS community. Today is is an excellent reference framework for how to structure a large-scale application with many of the core patterns necessary to build a system of decoupled modules that cleanly speak to each other.

Two years on, the maintainers of AuraJS agree that the future of decoupled, scalable applications lie in Web Components - a set of standards composed of Custom Elements, Templates, Imports and ShadowDOM, aimed at offering a way to build encapsulated components using features found in the browser.

To this end, our efforts on AuraJS moving forward will be focused on how it can help enable patterns for scalability in applications built with Web Components (using polyfills and libraries such as Polymer. This may take the form of several Aura 'elements' that can be easily included and reused in large projects.

Developers using AuraJS 0.9.2 and below will still be able to contribute to the current stable version of the project (there are large projects already built with it), however support for this version will be limited as we work on the designs for our next major version. We are more than happy to accept any contributions that meet our guidelines and will be reviewing the issue tracker for this version as time allows.

Our team are excited about the future direction of the project and look forward to announcing more news about our work here in the future.

Why Aura?

We've seen a large shift in the JavaScript community for the past 3 years, with people starting to write web apps in a much more structured way. Yet, assembling the bits and pieces and actually starting to make apps is still a challenge. Another challenge is that most of the time you end up doing the same stuff all over again : you need a way to authenticate users, give them ways to communicate, exchange ideas, work or play together. You have to integrate with external services or APIs like Facebook or Twitter.

Web apps are all about the end user experience (UI, DOM elements). The web development ecosystem is all about much more low level stuff. We need a way to package higher level abstractions and make them truly reusable, and that's what Aura is all about.

Need some more reasons to use Aura?:

  • It's basically glue for your application components, making it trivial to tie together a number of independently created components into a fully functional application.
  • A complete event-bus supporting application-level and component-level communication mean you have control over what is getting triggered in your app
  • Specify an API end-point for components easily and just use data-attributes to include any component or components. Minimal JavaScript for more capabilities.
  • Abstract away utility libraries you are using (templating, DOM manipulation) so that you can swap them out for alternatives at any time without a great deal of effort
  • Hit the ground running quickly components into reusable modules using AMD.
  • Bower is a first-class citizen in Aura, making it easier to manage your application dependencies
  • The web platform is moving towards using scoped styles and shadow DOM for keeping parts of your page safe from third-party content that might affect it. Aura does the same for communications by introducing per-component sandboxes for your events
  • Tooling for scaffolding out new components without having to write as much boilerplate
  • Can be used with your MVC framework of choice - we're just there as a helper.
  • First-class support for the Hull.io platform. If you don't want to create a component yourself, you can easily use them as a components-source and create apps in less time.
  • Extensible via the extensions system, which make a good basis for a rich ecosystem around the project.

Concepts

The Aura object

Your application will be an instance of the Aura object.

Its responsibilities are to load extensions when the app starts and clean them up when the app stops.

Extension

Extensions are loaded in your application when it starts. They allow you to add features to the application, and are available to the components through their sandbox.

Core

The core implements aliases for DOM manipulation, templating and other lower-level utilities that pipe back to a library of choice. Aliases allow switching libraries with minimum impact on your application.

Sandbox

A sandbox is just a way to implement the facade pattern on top of features provided by core. It lets you expose the parts of a JavaScript library that are safe to use instead of exposing the entire API. This is particularly useful when working in teams.

When your app starts, it will create an instance of sandbox in each of your components.

Component

A component represents a unit of a page. Each component is independent. This means that they know nothing about each other. To make them communicate, a Publish/Subscribe (Mediator) pattern is used.

Getting started

The simplest usable Aura app using a component and extension can be found in our boilerplate repo. We do however recommend reading the rest of the getting started guide below to get acquainted with the general workflow.

Requirements

  1. bower: run npm install -g bower if needed
  2. grunt-cli: run npm install -g grunt-cli if needed

Building Aura.js

  1. Run npm install to install build dependencies.
  2. Run bower install to install lib dependencies.
  3. Run grunt build and aura.js will be placed in dist/.

Running Tests

Browser

Run grunt. Then visit http://localhost:8899/spec/.

CLI

Run npm test.

Creating an Application

The first step in creating an Aura application is to make an instance of Aura.

var app = new Aura();

Now that we have our app, we can start it.

app.start({
  components: 'body'
});

This starts the app by saying that it should search for components anywhere in the body of your HTML document.

Creating a Component

By default, components are retrieved from a directory called components/ that must be at the same level as your HTML document.

Let's say we want to create a "hello" component. To do that, we need to create a components/hello/ directory

This directory must contain:

  • A main.js file. It will bootstrap and describe the component. It is mandatory, no matter how small it can be.
  • All the other files that your component needs (models, templates, ...).

For our "hello" component the main.js will be:

define({
  initialize: function () {
    this.$el.html('<h1>Hello Aura</h1>');
  }
});

Declaring a Component

Add the following code to your HTML document.

<div data-aura-component="hello"></div>

Aura will call the initialize method that we have defined in components/hello/main.js.

Creating an extension

Imagine that we need an helper to reverse a string. In order to accomplish that we'll need to create an extension.

define('extensions/reverse', {
  initialize: function (app) {
    app.core.util.reverse = function (string) {
      return string.split('').reverse().join('');
    };
  }
});

Using extensions

Extensions can then be loaded by your app by referencing them with their module name.

To make our reverse helper available in our app, run the following code:

This will call the initialize function of our reverse extension.

var app = Aura();
app.use('extensions/reverse');
app.start({ components: 'body' });

Calling use when your app is already started will throw an error.

Emitting and listening for event notifications

The Aura Mediator allows components to communicate with each other by subscribing, unsubscribing and emitting sandboxed event notifications. The signatures for these three methods are:

  • sandbox.on(name, listener, context)
  • sandbox.off(name, listener)
  • sandbox.emit(name, data)

Below we can see an example of a Backbone view using the Mediator to emit a notification when tasks have been cleared and subscribing to changes from tasks.stats in order to render when they are updated.

define(['hbs!./stats'], function(template) {
  return {
    type: 'Backbone',
    events: {
      'click button': 'clearCompleted'
    },
    initialize: function() {
      this.render();
      this.sandbox.on('tasks.stats', this.render, this);
    },
    render: function(stats) {
      this.html(template(stats || {}));
    },
    clearCompleted: function() {
      this.sandbox.emit('tasks.clear');
    }
  }
});

Debugging

To enable debug extension and logging pass {debug: {enable: true}} into the Aura constructor:

var app = new Aura({
  debug: {
    enable: true
  }
});

Logger usage:

// You can use logger from components or extensions
var logger = sandbox.logger;

logger.log('Hey');
logger.warn('Hey');
logger.error('Hey');

// Or directly from Aura app

var logger = app.logger;

Below we can see an example how to enable logging in specific ext/components. By default all loggers are enabled.

var app = new Aura({
  debug: {
    enable: true,
    components: 'aura:mediator login signup info'
  }
});

Built-in components:

  • aura:mediator - event logging.

Also, when debug mode is enabled, you can declare following function for any debug purposes:

// Function will be called for all Aura apps in your project
window.attachDebugger = function (app) {
  // Do cool stuff with app object
  console.log(app);

  // Maybe you want to have access to Aura app via developer console?
  window.aura = app;
};

Resources

Yeoman generator

An Aura scaffolding generator (for Yeoman) is also available at Aura generator.

Usage

  # First make a new directory, and `cd` into it:
  mkdir my-awesome-project && cd $_

  # Then install `generator-aura`:
  npm install -g generator-aura

  # Run `yo aura`, optionally passing an app name:
  yo aura [app-name]

  # Finally, install npm and bower dependencies:
  npm install && bower install --dev

Generators

Available generators:

Component

Generates a component in app/components.

Example:

yo aura:component sample

Produces app/components/sample/main.js

Extension

Generates a extension in app/extensions.

Example:

yo aura:extension storage

Produces app/extensions/storage.js

Styles

Generates cool styles.

Example:

yo aura:styles
Supported types:
  • Default (normalize.css)
  • Twitter Bootstrap
  • Twitter Bootstrap for Compass
  • Zurb Foundation

Examples

Want to look at some sample apps built with Aura? Check out:

Hullagram - an Instagram clone built with Aura and Hull.io.

An Aura TodoMVC app implemented two ways

Writing a simple GitHub component using Aura.

Aura Development docs

FAQs

Why do developers use us?

  • "The architecture and the fact that Aura Components are completely decoupled, will allow us to build an ecosystem of components that people can reuse internally or share with others."
  • "With ComponentSources and Require, we can load only the components that are needed by the app... at runtime."
  • "No JS is required to wire everything up, just include components with data-attributes in their markup"
  • "Mediation, same thing here it's a prerequisite to make everything decoupled... but in addition, it allows us to write much less code..."
  • "Template overrides FTW"

Contribute

See the contributing docs

aura's People

Contributors

addyosmani avatar asciidisco avatar atesgoral avatar bobholt avatar bolshchikov avatar buritica avatar c4milo avatar dcherman avatar dotcypress avatar drewzboto avatar dustinboston avatar eliperelman avatar gersongoulart avatar hkjorgensen avatar hmac avatar joelhooks avatar julien avatar karlwestin avatar oliger avatar peterudo avatar pickachu avatar robertd avatar robertusvt avatar rumpl avatar sbellity avatar sindresorhus avatar steffenmllr avatar tony avatar virtueme avatar xcambar 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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

aura's Issues

some questions and comments

I have some questions and comments about backbone-aura 0.8 developer preview.

  1. You placed every library in the lib directory expect require and require.text - is there a reason for that?
  2. I assume you used the name widgets because it fits your example but in a different use case this directory would not only contain widgets. You and Nicholas C. Zakas always talk about modules not widgets. I think it would be more understandable if you'd use the name modules instead of widgets.
  3. The same applies to facade and sandbox - the file is named facade.js and the alias sandbox.
  4. At the moment the example application is part of the whole project. It would be nice to have two parts: aura + example
  5. In the readme it says: "Widgets represent a complete unit of a page" - In my opinion the stylesheet should also be a part of that unit.
  6. What are the benefits of the permission-layer?
  7. The permissions get extended by simply using the extend function. Why not having the same ability on the mediator and facade? You could also get rid of the Object.create function in app.js.
  8. Why is there an alias for facade.start / -stop for the widget (facade.widget.start / -stop)?
  9. It's probably a bit early but it would be nice to have the ability to configure and customize aura with a configuration.
  10. There might be commonly used or inter-module models, collections, views, etc. in a project. How would you solve that?

That's it for now.
Thanks for the nice work and keep it up :-)

Logging capability

Hi,

I think it would be very nice if we can see what module publish/listens what events. Since Aura uses facade in between module and mediator, I think it is possible to make this happen.

I know that we can simply open each js files then check source codes, but it's just painful, especially working in a team environment with a lot of modules.

I've been using my own mediator in the following way.

Mediator.getOwnerOf("event name"); // returns owner of the event
Mediator.getListenersOf("event name") // returns listeners (modules) who listerns $eventanem
Mediator.getEventMapOf("module") // returns what $module listens and publishes.

Is there a plan for such feature?

Aura heavily bound with RequireJS + others... why?

As title says... why aura is so tight bound with RequireJS and jQuery and Underscore?

For example, the pup/sub technique that mediator uses shouldn't be bound so tight with RequireJS module autoloading and DOM selection as it is now, of course these are very useful, but only for those who use jquery + requirejs but thing is that not everyone uses (at least the second...).

I prefer to keep the following as the very basic example of mediator/facade pattern with permissions intermediate:

//==== Mediator Pattern
var channels = {};
var mediator = {};

mediator.subscribe = function (channel, subscription) {
  if (!channels[channel]) channels[channel] = [];
  channels[channel].push(subscription);
};

mediator.publish = function (channel) {
  if (!channels[channel]) return;
  var args = [].slice.call(arguments, 1);
  for (var i = 0, l = channels[channel].length; i < l; i++) {
    channels[channel][i].apply(this, args);
  }
};

//=== Permissions 
var permissions = {
  endContentEditing:{
    todoSaver:true,
    testing : true
  }
};

permissions.validate = function(subscriber, channel){
  var test = permissions[channel][subscriber];
  return test===undefined? false: test;
};

//=== Facade Pattern
var facade = facade || {};

facade.subscribe = function(subscriber, channel, callback){

  if(permissions.validate(subscriber, channel)){
    mediator.subscribe( channel, callback );
  }
}

facade.publish = function() {
  args = [].slice.apply(arguments, [0, 2]); // first two arguments for mediator
  arguments = [].slice.call(arguments, 2); // Rest for facade

  mediator.publish.apply(mediator, args);
}


//=== Application Use Case
facade.subscribe('todoSaver','endContentEditing', function (context) {
  try {
    console.loger('todoSaver');
  } catch (e) {
    console.log('todoSaver f**** up!');
  }
});

facade.subscribe('testing','endContentEditing', function (context) {
  console.log('testing');
});

facade.publish('endContentEditing', {
  test : 'test!'
});

Integrating the DOM-library (jquery, zepto, etc)

One way to make jquery more easily replaceable, is to reference jquery with a more generic name, like dom or something similar.
This is the approach I'm currently using in my app, to be able to switch between jquery and zepto more easily.

First the config can be changed to something like this:

require.config({
    paths: {
        dom: 'aura/lib/jquery'
    }
});

You could then replace:

define(['jquery', 'underscore'], function ($, _) {
    // ...
});

With this:

define(['dom', 'underscore'], function ($, _) {
    // ...
});

Of course, this is a compile-time step, thus it's not adding the ability to change the dom-library in the runtime, which would be another feature.
Just thought I'd share the idea.

Is there a way to compress all the js files into one file?

Hi,

I just tested out Aura and I really like it. One of my minor concerns is that requirejs optimizer simply compressed all the js files instead of generating one single js file.

Is this intended or is it going to be added in the near future?

Idea: Route events

From the last catch-up @dustinboston and I had about the project:

  • Routes that publish events
  • For example, a navigation widget gets clicked, modifies URL, e.g. /about
  • Route responds to URL change by publishing an event

Shared models/collections

Hi,

I post here my question because I think your answers will surely help someone else one day. It is a basic workflow which could be taken as an example for beginners I guess. Let's expose my question.

The example

Say, I've got a list of cars on my page. And when I click on a car, I see the information about the car displayed in an other part of my page and I can edit this information. Then, imagine I changed the name, so I want the row corresponding to the car being updated to display its new name.

My thought and the issue

First thought, it's easy when I update a model his own view is re-rendered! Issuer: Which architecture for this example... What I thought first was to develop two separate widgets:

  • The first one representing the list of cars
  • The second one to display the car details and edit it
    I wanted to build it like this because I read in the backbone preview written by addy osmani that each model should be in charge for a well defined job.

The first widget listen on the click and publish a message to the second one by passing in parameters the model "Car". But, here is the problem, the second widget doesn't know the model "Car" because it is defined in the first widget. And require this model by passing a weird reference such as "../my-first-widget/models/car" isn't good, because each widget should be able to live by his own.

Some other thoughts

I don't know which good architecture I should set up in this case:
1 - Set the whole first widget as a dependence of the second one?

2 - Make two widgets having both a model Car but the first one having (for instance), the name, and the second one, the name, the year, the constructor, the owner name. And when a car is edited, tell the first widget to refresh its whole list of cars.

3 - Make only one widget, and the second widget should only be another view of Car that I should display on my page when a car is clicked.

What are your advices?

ps: I really agree with @addyosmani and @dustinboston to say that the Todo example is too simple. It is good too understand the links between the scripts and the communication intra-widget, but not enough complex to being able to set up an architecture for a big project.

Uncaught TypeError: object is not a function

Hi. I have just downloaded aura and tried the new version in Google Chrome (it works in IE 9). Whenever I hit Eneter to create new todo item, I'm getting an error: Uncaught TypeError: object is not a function.
Here's the stack:

Uncaught TypeError: object is not a function
c.extend._prepareModelbackbone-optamd3-min.js:224
c.extend.createbackbone-optamd3-min.js:206
facade.subscribe.donemodules.js:75
obj.publishmediator.js:18
Backbone.View.extend.createOnEnterapp.js:72
f.event.dispatchjquery-min.js:1183
f.event.add.h.handle.ijquery-min.js:1103

Thank you.

Integrate Offline support

I'd like to integrate first class support for offline into Aura, something similar to:

https://github.com/Ask11/backbone.offline

At present, whilst offline isn't strictly a part of the originally planned architecture I strongly feel that there are advantages to giving developers the ability to use this out of the box.

To summarize: the way this works is that when a connection is no longer available we start syncing using local datastores (e.g localStorage), re-syncing with a server when a connection comes back.

example of facade.publish?

Just curious to see an example with facade.publish :)

EDIT:
I'm asking because I believe that facade.publish method should look more like this:

facade.publish = function() {
  mediator.publish.apply(mediator, arguments);
}

instead of this:

facade.publish = function(channel){
    mediator.publish( channel );
}

just want to confirm it :)

EDIT2:
Of-course we could also have something like this:

facade.publish = function() {
  args = [].slice.apply(arguments, [0, 2]); // first two arguments for mediator
  arguments = [].slice.call(arguments, 2); // rest for facade

  mediator.publish.apply(mediator, args);
}

since we expect mediator to get only two args we could pass first two args from facade and the rest will be used from facade if they needed.

In that way we will be using only Facade in our app and we won't call facade and mediator as it is now in the examples, so facade will invoke with mediator (since this is more logic as it is facade's role to invoke with private/hidden stuff).

Sharing Widget Data

Howdy,

Apologies if "Issues" isn't the right place for a question. If there's a better place to post, please let me know.

If two Aura widgets require same data, how should widget2 get widget1's data?

For example, let's say that the example project has a fourth "Feed" widget that displays a list of todos.

In Aura, how should the feed widget get the todos data?

  • Via mediator message?
  • Via separate collections defined in /widgets/feed/collections/ and /widgets/todos/collections/ ?
  • Via define(['sandbox', '../todos/collections/todos.js'], function(sandbox,Todos){})?
  • Something else?

Thanks!

Adam

Rename Aura Files

I think we should rename the aura files mediator.js to core.js and facade.js to sandbox.js as well as the main objects returned within these files (just like @addyosmani was going to do inside the single-file version). The reason is that, although it's important to know and understand which Js patters are being used (and that should still be explicit through the comments within the files), auras files (and objects returned) should be named after the functionality they're providing to the framework, not the technic adopted.

Stopping a widget not freeing memory/script?

I don't know if this is an issue with aura, requirejs, or chrome - but, it appears that scripts do not delete when you stop a widget. Worse yet, when you start the widget the script is duplicated. This duplication doesn't seem to show in the "Network" section in Chrome's Developer Tools, but it does show in "Scripts." Also, if you stop/start each widget multiple times while in the "Timeline" section (with record on), you'll see the memory climb.

For reference, memory seems to be at about 10mb after everything loads, but after stopping and starting each widget about 10 times the memory goes to about 30mb.

I'm not totally sure what it all means, but in the "Timeline" section, with the "Memory" option active, it appears that "listener" events fluctuates appropriately when stopping/starting widgets, but "nodes" climb each time a widget is started. I'd guess that means that event listeners are being removed correctly, but it seems like DOM elements aren't removed (aren't scripts DOM elements?). Makes me think that require.undef either doesn't work right or it's not be fired?

I checked and require.undef(key) is running when it should, but maybe the key is wrong? Or require.undef() just doesn't work like I would expect it to (I haven't it tested it on any of my projects, yet). I'll play with requirejs a bit and see if I can figure anything out.

De-fuglify with Bootstrap

Update HTML/CSS to use Bootstrap. @addyosmani Shall we integrate LESS and use the build step to generate the .css files? Or do you just want to stick with the pre-baked versions from le Twitter?

Update to new RequireJS errbacks

We currently have an outstanding TODO in mediator.js to switch over to the new error callbacks (errbacks). Below is a sample from the RequireJS docs on how this would work.

Notice that the errbacks are used from within your config and seem to best work where you know explicitly where you want to define a fallback for locally loading something, unloading the module you previously tried loading if it failed for whatever reason.

requirejs.config({
    enforceDefine: true,
    paths: {
        jquery: 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min'
    }
});

//Later
require(['jquery'], function ($) {
    //Do something with $ here
}, function (err) {
    //The errback, error callback
    //The error has a list of modules that failed
    var failedId = err.requireModules && err.requireModules[0],
    if (failedId === 'jquery') {
        //undef is function only on the global requirejs object.
        //Use it to clear internal knowledge of jQuery. Any modules
        //that were dependent on jQuery and in the middle of loading
        //will not be loaded yet, they will wait until a valid jQuery
        //does load.
        requirejs.undef(failedId);

        //Set the path to jQuery to local path
        requirejs.config({
            paths: {
                jquery: 'local/jquery'
            }
        });

        //Try again. Note that the above require callback
        //with the "Do something with $ here" comment will
        //be called if this new attempt to load jQuery succeeds.
        require(['jquery'], function () {});
    } else {
        //Some other error. Maybe show message to the user.
    }
});

Here is our current custom variation of this:

    require.onError = function (err) {
        if (err.requireType === 'timeout') {
            console.warn('Could not load module ' + err.requireModules);
        } else {
            // If a timeout hasn't occurred and there was another module
            // related error, unload the module then throw an error
            var failedId = err.requireModules && err.requireModules[0];
            require.undef(failedId);
            throw err;
        }
    };

which simply unloads a module if it fails.

What benefits do we gain from switching to the proper form of errbacks? Its clearer to the user how to specify local fallbacks? Keep in mind that such fallbacks will have to be defined by widget authors.

//cc @dustinboston

AMD+Opera

Hi, Addy!

I tried to check if it works in Opera 11.60.. and it seems that it doesn't:-( Do you know why?

Widget disposal

Is this enough for disposing a widget?

// Remove all modules under a widget path (e.g widgets/todos)
obj.unload("widgets/" + file);

// Empty markup associated with the module
$(el).html('');

what about unbinding events? Why is better to use $(el).html('') instead of $(el).remove() to remove the DOM nodes?
I've seen other frameworks, such as Chaplin or Marionette, having more sophisticated object disposal techniques.
Maybe I'm not understanding the full framework workflow here.

Esteban.

mediator publish function question

Hi there!

I was wondering about the publish function in mediator component.
This function iterates over the event's subsribers callbacks and executes them in sequence. My point is, if there are several subscribers for a single event and the first one's callback raises an error, I guess the rest of them won't be executed.
Is this so or am I missing something?

Thanks a lot for this brilliant work.

The best way to package an aura project

What would be the best way to package a large aura project with grunt?

  1. Optimize the "facade/core/dom/underscore/backbone" parts in an app-build.js file and then still require widgets (maybe also optimize each widgets deps to 1 main.js file).
  2. Same as (1) but wrap all widgets in one widgets-build.js file.
  3. One big app-build.js with both core and all widgets.

Any input is appreciated :-)

Project rename

We've discussed for a while the idea of renaming the project to Aura, eventually moving the Backbone-Aura extension part of it to a separate repo or just leaving it in the repo as a plugin of some sort.

As GitHub don't promise to handle redirects, renaming this repo would mean breaking links to articles pointing at backbone-aura, but otherwise should be okay. Anyone against this change?

modified source files with requirejs2.0?

is there a good reason to use the modified source files (backbone,underscore) instead of the shim feature of requirejs2.0?

this makes it harder for anyone to use a different version of backbone (especially master)

Idea: Media events

From the discussion with @dustinboston

  • Publish events on media change
  • E.g. when device is below 400px wide, trigger an even that tells the calendar to go into agenda mode
  • Could be based on matchMedia.js

Aura V1

I think it would be useful to discuss what should land in V1. We of course need docs and some more complete tests, but I'd be interested in hearing whether there are more features Aura should come with.

Some ideas:

  • Better widget/module memory management. Are we sure we're clearing all event handlers, DOM elements etc and can we confirm these efforts actually reduce the memory required by the page/widgets?
  • Should Aura be framework agnostic? Now that we've split up the demo into Aura, a Backbone extension and the demo I'm wondering whether we should put effort into getting Aura working with other frameworks.
  • Remove AMD dependency for Aura itself? I'm wondering whether the core Aura library (mediator, facade etc) should be offered as a non-AMD script that contains all three components that can just be dropped into a project. We can continue demonstrating the demo project with AMD but would just have Aura pulled in once rather than in three parts. Thoughts?
  • It was suggested that we should support dynamic loading of the CSS of a widget so that all dependencies are separate from each other. There are of course some browser-quirks that could make this challenging. Should we explore this idea?.

Any other ideas or comments on the above?

@dustinboston @rudolfrck @gersongoulart

Coding standard: Keep /* global */ jslint config in files?

Hi, was passing by and saw oppurtunity to make a pull, but wanted to step back and get a take on this.

Since we're using grunt configuration for handling jslint, we're set to allow for require, define, etc.

As a matter of consistency moving forward, should we include jslint comments at the top of backbone-aura files? It's missing on some, included on others, and outdated in other places.

Best
T

missing var statement

Hi Addy,

First thanks for sharing this, nice work.
Just wondering, on line 130 of the aura/mediator.js file you are using a variable named 'key' without declaring it:

obj.unload = function(channel){
        var contextMap = requirejs.s.contexts._.urlMap;
        for (key in contextMap) {
            if (contextMap.hasOwnProperty(key) && key.indexOf(channel) !== -1) {
                require.undef(key);
            }
        }

    };

Shouldn't that be ?

obj.unload = function(channel){
        var contextMap = requirejs.s.contexts._.urlMap, key;
        for (key in contextMap) {
            if (contextMap.hasOwnProperty(key) && key.indexOf(channel) !== -1) {
                require.undef(key);
            }
        }

    };

Cheers

Fix breaking build

Would you mind taking a look at this, @joelhooks ? I've been going through Travis CI trying to figure out where the build broke and everything seems to point to #71 and #72 being the culprits. Reverted those changes and applied some other minor changes but it still appears broken.

http://addyosmani.com/gyazo/0a8d.png

(It may be something very minor. I've been experiencing some npm issues this morning preventing me from running builds locally so any help would be appreciated)

Overextended modules

So I've really been having a problem with the models and collections in the aura-example. Circular dependencies, deferred hell, overly complex code, etc. It prompted me to go back and re-watch Nicholas Zakas' Scalable JavaScript Application Architecture presentation yet again. A couple of key points really stood out to me this time around:

  • Data is generally owned by a specific module. If another module needs that data the owner can send it to the mediator and then the mediator can distribute it out as needed.
  • If there is some data that is more general it can come from the application core and be exposed through a sandbox. I'm guessing something like user data, session info, and configs.

That combined with the principle that "any single module should be able to live on its own" got me re-thinking the way aura-example is structured.

I'm wondering if our example really isn't big enough. Everything we're doing currently centers around Todos. Sounds kind of like a single module. @addyosmani, you mentioned this sometime ago, and now I think I'm coming into agreement with you. Nicholas cites weather, stocks, and more. All very different types of data which correspond to different types of modules.

If we assume that Todos are just one Aura module, what would the mediator look like? I think pretty much the same. Same with the facade except that each module could possibly have its own instance of it. So then each AMD module within the Aura module includes the sandbox to get the functionality it needs like DOM manipulation, event handling, and AJAX. There is most likely a single entry point into that Aura module which, I think, would also be the one responsible for registering the Aura module with the core (mediator).

Just a side note: I think I get confusing because of the mixed terminology. To set the record straight, I'm proposing that we use many AMD modules to construct a single Aura module. I am using sandbox/facade interchangeably. Also I am using mediator/core interchangeably.

Seems a hell of a lot simpler to implement than my current approach. It also looks a lot like ender.js, but better because it provides an abstraction layer for all of the different APIs. Thoughts?

Language file

@addyosmani Just wanted to see what your thoughts regarding i18n are. It's not currently needed for our Aura because we're just throwing errors, but I think it would be great to expose a single nls file through the mediator/facade.

delete subscribers on aura mediator.stop?

Should the aura mediator.stop delete subscribers? - if you .start / .stop / .start the same widget it will have 2 duplicate subscribers.

    obj.stop = function(channel){

        var args = [].slice.call(arguments, 1),
            el = args[0],
            file = obj.util.decamelize(channel);

        // Remove all modules under a widget path (e.g widgets/todos)
        obj.unload("widgets/" + file);

        // Empty markup associated with the module
        $(el).html('');

    };

Shouldn't all subscribers be cleared aswell?

delete channels[channel]

maybe an prettier obj.unsubscribe fn instead :-)

Write README.md files for sub-directories as applicable.

It is really nice to have sub-dir READMEs in a project. When browsing on Github, it makes for an excellent supplemental narrative documentation. Aura is already aiming to be documentation heavy, but it is also appropriate to heavily document a project like this for educational purposes.

Should publish call start and inter-module communication

The mediator has two sets of functions that do a completely different thing:

  • subscribe/publish for inter-module communication
  • start/stop for loading/unloading of modules

I don't think those two should have anything in common.

The way it is today, when you publish something, say 'todos' in the example application, the application will load the todos widget. Also, sandbox.publish('todos', '#todosapp'); has the same effect as sandbox.widgets.start('todos', '#todosapp');.

I tried to make the calendar widget publish an event to say to everyone that a new event was created and make the todo widget add a new todo when this happens and made it only by changing a lot of stuff. You can see it on my branch here. There is still one thing that is not working: if you stop a widget, all its callbacks for the events should be cleared.

I am not sure I am doing the right think here but I was unable to find a way for modules to communicate (publish events and others to receive that event).

inter module communication

The major confusing point to me is between module communication. My previous understanding was - there are modules, that are absolutely independent each of other. The only one way to notify about something is to publish an event. They can subscribe to / publish on through mediator object.

Say, I have 2 modules - chat and message hub. Chat is basically backbone view, that is reposible for rendering messages. Message hub is module responsible for receiving and sending events.

Previously, I thought that mediator is responsible for providing functionality of Pub / Sub in aura architecture. With the latest changes, I can see it's not.

Some very simplified code,

// Chat
define(['core'], function (core) {
core.subscribe('chat', function () {
// create view here etc..

     // somewhere inside the view..
     core.subscribe('message/recieved', function () { });

});
});

// Message Hub

define(['core'], function (core) {
core.subscribe('hub', function () {
// somewhere is message recieve handler
core.publish('message/recieved', { messsage: data } );
});
});

But now, Mediator (or it's wrapper Facade) publish and subscribe methods has a different meaning. Publish is starting up widget and call it's subsriber function. The code like core.publish('message/recieved' ... ) will fail, since now it is expected 'widgets/message/recieved.js' module is expected. I think publish/subscribe loosing it's previous meaning.. now it's more like start / onStarted methods, as for me.

In my opinion aura now have a drawback that it does not demonstrate inter module communication which we can see in real life.

Idea: Prefetch/suspend

  • A widget can publish an event that will begin prefetching another widget
  • The widget will be loaded in a "suspended" state, meaning it's started but not displayed
  • A navigation widget could trigger an event to suspend several widgets and start others

@dustinboston when you get a chance would be great to get this idea expanded on :)

How to share collection

If i have one collection that uses many widgets, how correctly share this collection.

Sample:

Task menu (Wdiget?):

Review
In Progress
Done

Task list(Widget)
#1 Task name
#2 Task name
#3 Task name

Detailed view(Widget)

  • Task name
  • Description
  • created at

When in task list i click on "#2 Task name", i must render detailed view widget.
How correctly organize this code.

Thx.

facade.extend

Is there a facade.extend function example available that alters variables inside the module?

I'm not entirely sure if it is possible, but in my opinion you could respond to a channel inside a module with the facade.extend right?

I would love to start/stop/filter the module with this facade.extend but I can't seem to get this to work. A little code example would be dearly appreciated!

(im working with the new-version -- version)

Undefinded error when channel is missing in permissions

TypeError: rules[channel] is undefined

In https://github.com/addyosmani/backbone-aura/blob/master/src/aura/permissions.js#L26
var test = rules[channel][subscriber];

It happens when widget name is not added to permissions config and widget tries to subscribe to any event using sandbox.subscribe method. Of course we can add empty object just to avoid issue. In my opinion this could be simplified by returning false when there is no channel declaration in permissions config.

base lib abstraction

I'm not sure if you are aware of that:
If you want so switch the base lib, the interfaces of the sandbox (dom, utils, events, etc.) should be abstracted. I saw some cases where you referenced to the mediator which referenced the base lib's function directly (utils.extend = $.extend, etc.). Like that your widget code might not work if you switch the base library. But this can be avoided using proper abstraction in the sandbox.

Coding conventions

Coding conventions discussion based off #22, #81, #82. Making a stub for this.

We should make a wiki page to document decisions we have made throughout previous issues.

So far this includes:

  • Use of 2 spaces over tabs
  • Idiomatic.js concepts, unless objections in certain instances
  • Multiple var's in variable declarations
  • add anything else to a wiki page.

Some things to be discussed:

  • 'use strict'; vs "use strict"; per @sindresorhus on #82. 'use strict'; is valid and single quotes are clearer (see http://ecma262-5.com/ELS5_HTML.htm#Section_14.1).
  • Usage of new lines should be handled in context of the code at hand, but #82 does list a few newlines general approaches we can adhere to.
  • Not exhaustive, feel free to bring up anything else not listed here at anytime)

Hard time to build

Hey @addyosmani!

I got some errors while trying to build aura, not sure if everyone is going through the exact same, that's why I'm not trying to patch anything.

First error was on the lint task (on events.js, app.js and todos.js). But that's just a matter of minor adjustments in the files, so I didn't worry about it โ€” just removed the lint task from the grunt build and ran it again. Than I got:

Error: Cannot find module 'jsdom'

So I ran npm install jsdom in the same folder and ran grunt build again. Than I got:

Error: Cannot find module 'xmlhttprequest'

So I ran npm install xmlhttprequest in the same folder and ran grunt build again. Than I got:

RequireJS optimizer started

node.js:201
throw e; // process.nextTick error, or 'error' event on first tick
^
Error: Error: ENOENT, no such file or directory '/Users/gerson/Dropbox/Sites/backbone-aura/demo-build/js/ext/mediator.js' In module tree:

The app seem to be working just fine, but I don't understand this error. I wish I could help better and give a solution, but it will take me a while until I wrap my mind around all the RequireJS thing...

What is the software license which covers Aura ?

Hello,

i want to use some of this library in another project, but i need to make sure the license agreement is in alignment. What is the software license you are using to cover this project ?

Cheers,
David

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.