aurajs / aura

A scalable, event-driven JavaScript architecture for developing component-based applications.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for loading of individually optimized components?

opened this issue · comments

main.js

var app = new Aura({
    sources: {
      'default': './aura_components',
      'ektron': './aura_components/ektron'
    }
  });

  app.start([{
    name: 'toolbar@ektron',
    options: {
      el: '#ektron-application-host'
    }
  }]).then(function() {
    console.log('Aura started...');
  });
});

aura_components/ektron/toolbar/main.js

define(['text!./toolbar.html', 'css!./toolbar.css'], function(template) {
    return {
        initialize: function() {
            this.html(template);
        }
    };
});

In this scenario where the second file(the component) has been optimized using r.js, the application fails to call initialize on the component. The optimized file(which includes the component and all of its dependencies) is actually loaded, but in never materializes in the dom.

Is this not a supported scenario or am I missing something obvious. The main requirement here is all of the components be optimized individually so that they can be lazy loaded from the main application.

Is #332 possibly related to this, @joshspivey?

The root cause of this issue is here: https://github.com/aurajs/aura/blob/master/lib/ext/components.js#L317
The module name doesn't match the package name so the "component definition" is empty and thus rejects the deferred. Changing the module definitions name(in the optimized file) to match the one that is generated for the package resolves this issue, but this isn't a viable solution.

I'm going to look into a more robust fix.

notes for reference:
This is also related to #66. I may want to include an updated version of the script which creates the module config in the grunt file.

Also, #47 #47 (comment)

@danmartinez101 not sure I understand what you are trying to do. But it sounds like you need to use esprima to parse the compiled components. This is how require does it.

Or it sounds like your arguments are getting rewritten because of the minification script you are using you might need a externs file or just use uglify...

@danmartinez101 is there a flow chart for Aura?

@sbellity @danmartinez101

So this is what needs to be done...

each component needs a config variable, in the view/controller. asyncComponent = true or something. Use esprima. Traverse the modules for the property with a grunt task. If its async then you copy it to async location and register it with escodegen. If the component is not async then compile it in with almond/require rjs optimizer if there is one module that is async then you can use almond. Now you can cherry pick what you want to be compiled in on build and what you want to be async.

    //traverse method for spider monkey format
    //http://sevinf.github.com/blog/2012/09/29/esprima-tutorial/
    traverse: function(node, func) {
        var self = this;
        func(node);//1
        for (var key in node) { //2
        if (node.hasOwnProperty(key)) { //3
            var child = node[key];
            if (typeof child === 'object' && child !== null) { //4

            if (Array.isArray(child)) {
                child.forEach(function(node) { //5
                     self.traverse(node, func);
                });
            } else {
            self.traverse(child, func); //6
             }
             }
        }
        }
    },

Interesting idea.
We have a different approach though at @hull :

We use this very simple grunt task : https://github.com/hull/grunt-hull-widgets to individually build all the components found in a directory and publish them individually. The whole directory is a components source...

The other trick that we use is that we expose a method called Hull.component that "registers" a component's definition in requirejs registry, which makes it possible to require components asynchronously in dev and just concatenate / minify them if you want in production.

Have a look at https://github.com/hull/hullagram to see how it works (even if this demo is pretty old and still uses "widget" instead of "component").

Our issue is that a ton of developers don't use tooling at all, don't know anything about AMD... I think we need to support workflows that work well even without explicitly using AMD and r.js

Cool! Thank you both for the information. I'm going to go chew on that and see if I can make either of these work in the environment I have here.

@sbellity @danmartinez101

This is great we can combine the 2 methods together to give more flexibility. Sbellity has applications that needs to be loaded in async most of my app's need to be compiled with RJS optimizer. I will have to prioritize this update but I have most of the code to do this already I use pretty much the same process to grab templates and precompile them I can combine the 2 tasks together when I do the template system update for aura. The issue I found with compiling folders is you dont know what is being ran or what is used in your application I used to do that with my templates but then I would start to make more advanced multi page apps that where not apart of the same single page app in a code base. So what I did it take rjs.tools.useLib(function(require) { in a grunt task to see what I was actually using within the scope of the loaded project so I can share code structure for more advanced applications because I was getting templates compiled in that where not being used and that was waisting bandwidth.

There's a simple, r.js-only solution to this problem. You just need to ensure that the optimized component ends up having the same path as its ultimate path within an Aura project. For instance, if the component will end up under aura_components/foo, then instead of getting it optimized as foo (i.e. define('foo', ...)), you can get the component optimized as aura_components/foo by adding a path mapping and then indirectly referring to your component in app.build.js:

{
    paths: {
        'aura_components': '.'
    },
    modules: [ 'aura_components/foo' ]
}

I've used this method successfully in a pluggable application where individually optimized plugins could be placed into a "plugins" directory and just work without any further magic.

@atesgoral this is perfect I dont see any info on it in RJS docs tho :( but I do see bundles... So this loads in the module ASYNC?

Indeed that would be perfect !
Let's try to put together a small demo ;)
On 29 Jan 2014 21:31, "Josh Spivey" notifications@github.com wrote:

@atesgoral https://github.com/atesgoral this is perfect I dont see any
info on it in RJS docs tho :( but I do see bundles... So this loads in the
module ASYNC?

@sbellity https://github.com/sbellity @danmartinez101https://github.com/danmartinez101
Maybe should get a fiddle going so we can test these options out and see
how nice they place with Almond here is a Primer
http://jsfiddle.net/wellcaffeinated/9knfL/1/

Reply to this email directly or view it on GitHubhttps://github.com//issues/334#issuecomment-33627297
.

@danmartinez101 @sbellity @atesgoral

I really like this solution allot that atesgoral has provided. It wasn't really clear in the docs because it was on the optimization page. I guess you need to make a build profile.

http://requirejs.org/docs/optimization.html

Here is a boilerplate that uses this technique. Maybe we should make a fiddle so we can fix this together. And we should keep in mind the ability to swap in almond.

https://github.com/mdezem/MultiPageAppBoilerplate/blob/master/build/build.js

https://github.com/mdezem/MultiPageAppBoilerplate

I did go down the paths route to make the optimized module name match what the the main aura app was requiring, but ran into a roadblock with that because the optimized module is actually an entire application on its own.

I started hacking together a solution that creates a new require context for each component so that they are sandboxed. I haven't had time to really dive into this again since I'm slammed during the week at work, but I'm going to try to carve out some time this weekend.

btw, @joshspivey do you work at the same lbox as Brad and Ryan out in cali?

@danmartinez101 yes I do they sit right next to me :) its a small world...

@danmartinez101 @sbellity @relston @atesgoral I forked todo MVC and added all of you as collaborators so we can get this requirejs issue resolved.

My end goal is to use requirejs for modules and be able to use almond along with a async method that can be turned on maybe we have a extension for this. Since no one has a flow chart I am going to work on the new proposed module structure. One big thing I see being a issue is module registration. If you use the data-attribute route you will not be able to compile files in together so this is the big problem that needs to be solved. Me personally I am fine with manually registering modules but its better to auto reigster. If we auto reigster modules we will have to have some sort of grunt task so we can have file system functions doing the registering for us. A really good auto loader I have used in the past is on ZF2, I know Yii has one as well, django and most other frameworks I still have to manually register modules. The way ZF2 works is it reads your file structure and it reads a scaffolding config file, similar to a json file. So I am thinking we can use the requirejs build files for the modules as the scaffolding file. I will post a new design proposal soon with a flowchart collaboration site like http://flowchart.com/

http://framework.zend.com/manual/1.12/en/zend.loader.autoloader.html

@danmartinez101 @sbellity @relston @atesgoral Oh yah here is the repo
git@github.com:joshspivey/todomvc.git