Durandal *requires* multiple <script> tags and global pollution?!

2,372 views
Skip to first unread message

Darren Slatten

unread,
Apr 4, 2013, 7:59:16 PM4/4/13
to duran...@googlegroups.com
This topic has been discussed in a couple other threads, but I don't feel like it's been resolved. So if I may, I'd like to initiate a more in-depth conversation about the pros/cons of one of Durandal's design decisions: using <script> tags to load 3rd-party libs (e.g., jQuery, Knockout, and Sammy) and only using AMD/require.js to load Durandal's modules.


[index.html]

...
    <body>
        <div id="applicationHost"></div>
        
        <script type="text/javascript" src="Scripts/jquery-1.9.1.min.js"></script>
        <script type="text/javascript" src="Scripts/knockout-2.2.1.js"></script>
        
        <!--Durandal's core does not require SammyJS. The router plugin uses it.-->
        <script type="text/javascript" src="Scripts/sammy-0.7.4.js"></script>

        <script type="text/javascript" src="app/durandal/amd/require.js" data-main="app/main"></script>
    </body>
</html>


Personally, I don't like this aspect of Durandal. I'd much rather use AMD/require.js to load everything (i.e., allow index.html to use a single <script> element). Unfortunately, Durandal is written in a way that assumes ko is globally defined. In other words, Knockout MUST be loaded via a <script> element in index.html, before main.js is loaded. Otherwise, Durandal's modules fail.

AFAIK, in order for Durandal to be completely executable through a single script element (and keep the global namespace clean), it would need to be modified such that all Durandal modules require jQuery and ko. In other words, changing this design aspect isn't exactly trivial--it would mean modifying several core Durandal files. Therefore, I think we should discuss the pros/cons of such a change and determine (once and for all) whether or not it would be appropriate.

I think Durandal should definitely change to a pure AMD architecture, so I'll begin the discussion by providing my own reasoning. Also, as a side note, I'll mention that I'm only using Durandal in the browser. Some of the benefits listed below might be attainable through a server build/optimization, but I'm assuming it's desirable for Durandal to accommodate high performance without requiring a server.



1.  Keep the global namespace clean

Correct me if I'm wrong, but wasn't "global namespace pollution" one of the driving forces behind modular JS in the first place? It just seems really wrong to me that Durandal uses AMD/require.js and then forces developers to disregard the best practices AMD was designed to enforce. But more importantly, Durandal should change to a pure AMD architecture because it would allow for use cases where multiple versions/instances of jQuery and Knockout are present in the same document. Currently, Durandal assumes that $ and ko won't be used/modified by something else on the page; is that always a safe assumption? No.



2.  Lazy-load the entire app

For the project I'm working on, index.html loads default content that doesn't have any JavaScript dependencies. Durandal kicks off after the page is done loading that default content (and optionally, after a User-initiated event, e.g., "Click here to load the application"). This allows for a very fast perceived load time, which is especially important for mobile devices. However, this is not possible with Durandal's current design (at least not without writing a significant amount of custom code).



3.  Faster (perceived) page load

Even without lazy-loading, the perceived page load time can be significantly improved by using require.js to load 3rd-party scripts. By loading jQuery, Knockout, and Sammy with require.js (via a single script tag right before </body>), I was able to reduce the page load time (measured by the document's load event) from 4.2 seconds to 1.2 seconds.



4.  CDN with local fallbacks

Using the require.config paths configuration, let the app load 3rd-party scripts from a CDN; fallback to Durandal's copies. Example:


require.config({
    enforceDefine: true,
    paths: {
        'text': 'durandal/amd/text',
        jquery: [
            '../Scripts/jquery-1.9.1.min'
        ],
        knockout: [
            '../Scripts/knockout-2.2.1'
        ],
        sammy: [
            '../Scripts/sammy-0.7.4'
        ]
    }
});



Please...if anyone has anything to add here, feel free to chime in. I'm especially interested in hearing reasons for keeping Durandal the way it is (i.e., loading 3rd-party scripts via <script> tags and polluting the global namespace).





Rainer Wittmann

unread,
Apr 5, 2013, 5:35:36 AM4/5/13
to duran...@googlegroups.com
My main argument to keep Durandal the way it is, is a pretty personal: It feels good when writing code.

But here are some other, just in case that's not convincing enough for you :).

1. Citing http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailamd

The overall goal for the AMD (Asynchronous Module Definition) format is to provide a solution for modular JavaScript that developers can use today.

Keeping the global namespace clean is a side effect when using AMD, not the main goal. If you consider third party libraries as global resources that are used by all modules, it does make sense to me to make them available globally.
Regarding multiple version of the same libraries: Won't happen in a SPA as you control the app, might happen in when deploying widgets. If that's the case then you've to deal with that situation even when using shims. Citing from https://github.com/jrburke/requirejs/wiki/Upgrading-to-RequireJS-2.1

requirejs.config({
    shim: {
        'foo': {
            deps: ['bar'],
            exports: 'Foo',
            init: function (bar) {
                //Using a function allows you to call noConflict for
                //libraries that support it, and do other cleanup.
                //However, plugins for those libraries may still want
                //a global. "this" for the function will be the global
                //object. The dependencies will be passed in as
                //function arguments. If this function returns a value,
                //then that value is used as the module export value
                //instead of the object found via the 'exports' string.
                return this.Foo.noConflict();
            }
        }
    }
});


2. Lazy load especially for mobile apps? You might consider using  https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache to cache the required infrastructure files. 

3. - 4. For production version consider Bundling/minifying the CSS and third-party JS files and create an optimized build for your Durandal app. 



Joseph Gabriel

unread,
Apr 5, 2013, 12:11:08 PM4/5/13
to duran...@googlegroups.com
For us ASP.NET MVC developers, one of the disadvantages with requiring the standard libraries is that it would negate the ability to use ASP.NET Bundles to package up libraries.  I like the idea that the standard libraries (KO, Jquery, Sammy, etc) can be cached separately in the browser.  Maybe that's just my .Net mindset getting in the way.

Darren Slatten

unread,
Apr 5, 2013, 4:40:38 PM4/5/13
to duran...@googlegroups.com
 
1. Citing http://addyosmani.com/resources/essentialjsdesignpatterns/book/#detailamd

The overall goal for the AMD (Asynchronous Module Definition) format is to provide a solution for modular JavaScript that developers can use today.

Keeping the global namespace clean is a side effect when using AMD, not the main goal.

I definitely don't think it's merely a side effect. I think most developers--including Addy Osmani--would consider it a defining characteristic of AMD. The following excerpt is from Addy's article, Writing Modular JavaScript With AMD, CommonJS & ES Harmony. I emphasized the part where Addy identifies namespace collisions as one of the weaknesses AMD is intended to address.

Unlike some more traditional programming languages however, the current iteration of JavaScript (ECMA-262) doesn't provide developers with the means to import such modules of code in a clean, organized manner. It's one of the concerns with specifications that haven't required great thought until more recent years where the need for more organized JavaScript applications became apparent.

Instead, developers at present are left to fall back on variations of the module or object literal patterns. With many of these, module scripts are strung together in the DOM with namespaces being described by a single global object where it's still possible to incur naming collisions in your architecture.


And later, from the same article:

Why Is AMD A Better Choice For Writing Modular JavaScript?
    • Provides a clear proposal for how to approach defining flexible modules.
    • Significantly cleaner than the present global namespace and <script> tag solutions many of us rely on. There's a clean way to declare stand-alone modules and dependencies they may have.
    • Module definitions are encapsulated, helping us to avoid pollution of the global namespace.
    • Works better than some alternative solutions (eg. CommonJS, which we'll be looking at shortly). Doesn't have issues with cross-domain, local or debugging and doesn't have a reliance on server-side tools to be used. Most AMD loaders support loading modules in the browser without a build process.
    • Provides a 'transport' approach for including multiple modules in a single file. Other approaches like CommonJS have yet to agree on a transport format.
    • It's possible to lazy load scripts if this is needed.



2. Lazy load especially for mobile apps? You might consider using  https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache to cache the required infrastructure files.

What I mean is...it's important for index.html to load (i.e., fire the document load event) as quickly as possible. If index.html provides no additional content or functionality (i.e., the <body> only contains the <div id="applicationHost"></div> element, then the benefits (in terms of User experience) will be minimal. However, if index.html contains default (i.e., hard-coded HTML) content and <div id="applicationHost"></div> is just one element in the page (similar to a scenario where the app is embedded in a host page like a widget), then the UX benefits would be much more noticeable. Specifically, the User would be able to read/scroll/interact with the default HTML content while the app loaded in the background.



3. - 4. For production version consider Bundling/minifying the CSS and third-party JS files and create an optimized build for your Durandal app.

Yes, that's possible...but the real question is: shouldn't Durandal be able to perform well as a standalone JavaScript library? Personally, I think Durandal should be fully functional without depending on server integration or a build step. The main reason for that: I'd like to be able to host an app with Github (Pages), which would allow others to easily fork the app, modify it, and have their own version up and running within a matter of minutes--all from Github's Web interface. Admittedly, that's probably not a common use case, but nevertheless, it's a real example of a use case that isn't possible if Durandal apps require a build step.

Also, note that Addy Osmani included the following bullet point in his list of reasons why AMD is better for writing modular JavaScript:

    • Works better than some alternative solutions (eg. CommonJS, which we'll be looking at shortly). Doesn't have issues with cross-domain, local or debugging and doesn't have a reliance on server-side tools to be used. Most AMD loaders support loading modules in the browser without a build process.

Lastly, I'll mention that my #4 reason for loading 3rd-party scripts via require.js was that it provides a convenient mechanism for loading scripts from a CDN while providing local fallback paths. The benefits of using a CDN can't be achieved through bundling/minifying/optimizing an app, so as far as I can tell, #4 still stands as a limitation of Durandal's current design.

Darren Slatten

unread,
Apr 5, 2013, 4:49:12 PM4/5/13
to duran...@googlegroups.com
For us ASP.NET MVC developers, one of the disadvantages with requiring the standard libraries is that it would negate the ability to use ASP.NET Bundles to package up libraries.  I like the idea that the standard libraries (KO, Jquery, Sammy, etc) can be cached separately in the browser.  Maybe that's just my .Net mindset getting in the way.

I'm not sure I understand. I've never used .net, but I'm assuming that bundles are multiple scripts, minified and concatenated into one file? If that's the case, then how would a browser cache them as separate files?

Joseph Gabriel

unread,
Apr 5, 2013, 8:07:04 PM4/5/13
to duran...@googlegroups.com
you're right - I meant separately from the Durandal app files.  I can definitely see where you're coming from, though.  It would be nice to support both options.

Rainer Wittmann

unread,
Apr 6, 2013, 6:04:21 AM4/6/13
to duran...@googlegroups.com
#4: If CDN first, local fallback is important you can implement that on your own http://stackoverflow.com/questions/5257923/how-to-load-local-script-files-as-fallback-in-cases-where-cdn-are-blocked-unavai

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.5.1.min.js">\x3C/script>')</script>
In the same article you find a reference to http://yepnopejs.com/

yepnope([{
  load: 'http:/­/ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js',
  complete: function () {
    if (!window.jQuery) {
      yepnope('local/jquery.min.js');
    }
  }
}]);
#3 Without building an optimized version of your Durandal's app you won't be able to run at the optimized performance. Disable browser cache and see the network load on your own.

For your use case people can fork and develop using github's web interface. In order to produce  a production version they have to clone the fork and run optimizer.exe or a mimosa built depending on the platform they are running. At that point they have to go the command line I've to admit.

#2 Consider using a splash screen that emphasize that your app isn't ready yet. Turn on the browser cache again and visit the sites above again. On second visit the splash screen is barely noticeable.

#1 Looks like I won't be able to convince you on that one, so let's leave it with I'm happy with Durandal's pragmatic defaults as those reflect my personal experience.

Rainer

dbas...@gmail.com

unread,
Apr 6, 2013, 8:21:06 AM4/6/13
to duran...@googlegroups.com
Original poster, +1

Darren Slatten

unread,
Apr 6, 2013, 4:55:33 PM4/6/13
to duran...@googlegroups.com
#4: If CDN first, local fallback is important you can implement that on your own

That is true, but the alternative implementations you're suggesting are not elegant, and they violate best practices:
  • Uses inline JavaScript
  • Uses document.write
  • Isn't DRY. That is, it requires loading/executing extraneous code to accomplish something that's already provided by require.js.
Summary:  Durandal is currently designed in such a way that it limits the native functionality of require.js, and the only way to recover that functionality is by writing ugly code.



#3 Without building an optimized version of your Durandal's app you won't be able to run at the optimized performance.

That may be true in most cases, but not all cases. The issue, however, isn't performance per se; it's flexibility. Loading vendor libs through AMD/require.js would not limit developers' options for creating optimized builds. In other words, Durandal would gain flexibility and lose nothing. The opposite is not true, however: forcing developers to build Durandal apps on a server does limit flexibility (e.g., Github Pages).

Also, if performance is being measured by the amount of time it takes index.html to fire the load event, then Durandal's current design is preventing apps from achieving optimal performance, because it forces you to load vendor scripts in a manner that blocks the load event.*

* Some people are probably reading this and thinking: "Who cares about index.html's load event if Users can't even see/use the app yet?" There are 2 reasons why this is important:
  1. Perceived page speed: most browsers show a loading... icon until the page fires the load event. (Also, I've read somewhere that some mobile browsers don't let Users scroll down the page until the load event has fired. This can give Users the impression that the page is frozen. I haven't verified/witnessed this myself, however.)
  2. Google rankings: Google has publicly stated that page load times are used in its ranking algorithm. It measures page load times through the Google Toolbar, using the load event as the indicator that a page is done loading.
Summary:  Durandal is currently designed in such a way that it prevents developers from achieving optimal performance, it prevents developers from using RequireJS's lazy-loading capabilities, and it prevents index.html from achieving optimal rankings in Google's search engine results.



#2 Consider using a splash screen that emphasize that your app isn't ready yet. Turn on the browser cache again and visit the sites above again. On second visit the splash screen is barely noticeable.

A splash screen can help improve perceived page load times, but it is not a substitute for lazy-loading.

Rainer Wittmann

unread,
Apr 7, 2013, 9:44:54 AM4/7/13
to duran...@googlegroups.com
First of all I'd like apologize that my attempt to offer a solution for  your specific use case didn't find your liking.

So here are two other options that come to my mind.
  1. Use requirejs to load the files as you described above. In main.js define them as dependencies and attach them to globals. Yeah, I hear you, I'm evil again, but that way you wouldn't have to change any Durandal file as it them as global anyway. Please note that you most probably have to tweak r.js / optimizer.exe a little to exclude those files from an optimized build.
  2. Fork Durandal. 


On Saturday, April 6, 2013 10:55:33 PM UTC+2, Darren Slatten wrote:
#4: If CDN first, local fallback is important you can implement that on your own

Darren Slatten

unread,
Apr 8, 2013, 1:05:25 PM4/8/13
to duran...@googlegroups.com
There's no need to apologize. I appreciate your feedback. But my objective in this thread isn't to find workarounds or solutions for my specific problems. My objective is to discuss whether or not Durandal should be refactored such that it doesn't depend on global variables (aside from require/define, of course) or build/optimization steps, and it doesn't assume that app developers have complete control over the host page (i.e., index.html). In its current state, Durandal is limiting the range of use cases that it's suited for, and it's forcing developers to misuse RequireJS/AMD. And as far as I can tell, the only justification for it is that it allows some developers to take shortcuts.

So yes, I can always just modify Durandal to suit my personal needs, but I'd rather help make Durandal better for everyone.

Evan Larsen

unread,
Apr 10, 2013, 9:26:48 PM4/10/13
to duran...@googlegroups.com
Hey, yall have all made really good points and I really enjoyed reading this.  I would like to chime in and share something too.

I have a friend who is using durandal and he is working on making a plugin for other websites where they can just drop his spa in their website and it adds a widget to their site.  But to get this accomplished he needs to make sure that he doesn't interfere with what version of jQuery & Knockout that site is already using. So, for his scenario it makes sense to have everything as AMD as to not overwrite the hosting sites libraries and also not depend on the host site already having the correct version of Knockout & jQuery.

I guess this scenario would go inline with not polluting the global namespace.  Just thought I would share a scenario my friend has encountered.  :)

Tom McKearney

unread,
May 30, 2013, 9:57:12 AM5/30/13
to duran...@googlegroups.com
I agree that it should be purely AMD. It feels like a hybrid now. It doesn't seem like it would be that difficult to do, just a bit of extra work, right?

I might fork it to see if I can pull it off easily and see what Rob E thinks about it.

T

Tom McKearney

unread,
May 30, 2013, 1:12:20 PM5/30/13
to duran...@googlegroups.com
Then again, this would require bundling jquery, knockout and bootstrap with durandal, wouldn't it?

Or would you just make it so the code just has to declare the requirejs.config block to define knockout, jquery and bootstrap variables?

Tom McKearney

unread,
May 30, 2013, 1:26:56 PM5/30/13
to duran...@googlegroups.com
Yes, I know I'm talking to myself, but ... :)

If we make it that users must set this up, it works fine (have a local copy working like this)

requirejs.config({
    paths: {
        'text''durandal/amd/text',
        'knockout''../Scripts/knockout-2.2.1',
        'bootstrap''../Scripts/bootstrap',
        'jquery''../Scripts/jquery-1.9.1'
    },
    shim: {
        'knockout': {
            exports: 'ko'
        },
        'jquery': {
            exports: '$'
        }
    }
});

Tom McKearney

unread,
May 30, 2013, 1:49:00 PM5/30/13
to duran...@googlegroups.com
FYI: I created an Issue for this so we can associate some of this info with code changes if this occurs


On Thursday, April 4, 2013 7:59:16 PM UTC-4, Darren Slatten wrote:

Darren Slatten

unread,
May 30, 2013, 3:30:15 PM5/30/13
to duran...@googlegroups.com
Personally, I think Durandal should be packaged more like a client-side AMD-compatible library and less like a server tool. Doing so would greatly improve its flexibility, especially for developers who aren't using the (server-based) optimizer script. Changes I'd like to see:

  1. No capital letters in directories that form URL paths (e.g., "/App", "/Scripts")
  2. Vendor libs in dedicated directories (for easier upgrades of 3rd-party dependencies)
  3. Durandal treated like a vendor (i.e., "my app uses Durandal, jQuery, and Knockout" instead of "my Durandal app uses jQuery and Knockout")

A demo that I built (to demonstrate something tangentially related) satisfies most of these criteria: LazIE  It's not a perfect example, but I think it makes a lot more sense than Durandal's current structure. (Note: the vendor libraries in that demo are in /lib.) An intuitive, web-ready directory structure like this naturally lends itself to following AMD best practices, including keeping the global namespace clean. It also reinforces the basic principles of modular design, by keeping "my app" code separate from Durandal, and keeping Durandal separate from the libraries it depends on.

Darren Slatten

unread,
May 30, 2013, 6:30:57 PM5/30/13
to r...@bluespire.com, duran...@googlegroups.com
Yes, I can do that.

I'm also creating a new fork that can serve as a better example (i.e., better than the one I linked to previously). One of the things I'm considering is whether or not it would be beneficial to use Submodules for managing 3rd-party libs with git. I've never dealt with git submodules, but it sounds like a good fit for Durandal's needs--with the downside (apparently) being an increase in complexity.

Might be worth looking into?



On Thu, May 30, 2013 at 2:39 PM, Rob Eisenberg <r...@bluespireconsulting.com> wrote:
Can you create an issue for this and attach the provided link there. It is definitely something that is being considered...


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
Rob Eisenberg,
President - Blue Spire
www.durandaljs.com



--
Darren Slatten

Maxime Séguin

unread,
May 31, 2013, 9:26:02 AM5/31/13
to duran...@googlegroups.com
As much as I enjoy Durandal lately, I agree 100% with Darren on this one... and I happen to have a similar need to his friend.

I hope Durandal offers possibilities in that vein in a near future, as a fork or not (preferably). 

Maxime Séguin


On Thursday, April 4, 2013 7:59:16 PM UTC-4, Darren Slatten wrote:

Tom McKearney

unread,
May 31, 2013, 3:09:22 PM5/31/13
to Maxime Séguin, duran...@googlegroups.com
Well, it's basically in the works now.  Rob is looking at my pull request.  We'll see how it goes from there.



--
You received this message because you are subscribed to a topic in the Google Groups "DurandalJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/durandaljs/a4GVyHKzfDk/unsubscribe?hl=en.
To unsubscribe from this group and all its topics, send an email to durandaljs+...@googlegroups.com.

Steve Gentile

unread,
May 31, 2013, 4:09:26 PM5/31/13
to duran...@googlegroups.com
I would agree to this as well, I'm seeing 'ko' all over - and would prefer to see those dependencies - it's especially problematic when using another frameworks asset pipeline


On Thursday, April 4, 2013 7:59:16 PM UTC-4, Darren Slatten wrote:

Darren Slatten

unread,
May 31, 2013, 11:05:48 PM5/31/13
to duran...@googlegroups.com
Hey Rob,

I forked Durandal (again) and I have started molding it into what I consider to be the perfect structure. I call it... Darrendal!

=P

Here's the forked repo.


Here are a few bullet points:

  1. To reinforce the separation of client-side resources and server tools, I created a top-level directory, called /Web, which I'm treating as a "public web root directory". All the resources in the /Content and /Scripts directories were either moved under /Web or replaced by newer versions. As far as I know, this will not interfere with the server tooling, but it will greatly diminish the learning curve for new devs who want to try Durandal in the browser.
  2. Durandal's AMD modules are treated as 3rd-party content, just like RequireJS, jQuery, Knockout, Sammy, etc.
  3. All 3rd-party content (including Durandal's client-side core) is located under /lib. This is basically a "vendor" directory. No more separating dependency libraries into various places.
  4. 1st-party content (i.e., my app code) is located under /app. In the live demo, I'm just using the code from your Samples app. I feel that it's important to keep Durandal's core entirely separated from "my code". In theory, this structure would allow developers to easily host multiple Durandal-based SPAs on the same website.
  5. Plain JavaScript files (i.e., my scripts that are used on the website but aren't part of my app) are located in /js. There's one file in there currently, called init.js, which I'm using to demonstrate lazy-loading the entire app. This supports the "SPA as a widget" use case that a few folks have mentioned. It also provides the ability to load an entire app after a user-generated event (e.g., "click here to load the app"). (Plus...no script tags in the footer!)
  6. I've updated all Durandal and Samples files to declare their ko dependency via RequireJS. (jQuery, Sammy, Bootstrap, etc. will follow shortly.)
  7. The fork has 2 branches: my master directly correlates with your master, but my gh-pages is a copy of the /Web top-level directory I created in my master. To put it simply: I used the gh-pages branch to demonstrate that Darrendal actually works.

ALL FEEDBACK WELCOMED!  :)

Rainer Wittmann

unread,
Jun 1, 2013, 5:10:38 AM6/1/13
to duran...@googlegroups.com
Like it. 

With the latest version of Durandal, there's no need to include sammy.js any longer.
What is the vision for the build step? Would that include or exclude external libs?

Rainer Wittmann

unread,
Jun 1, 2013, 8:27:09 AM6/1/13
to duran...@googlegroups.com
I created a comment on the pure AMD thread https://github.com/BlueSpire/Durandal/issues/163#issuecomment-18788183 for better tracking.


On Saturday, June 1, 2013 5:05:48 AM UTC+2, Darren Slatten wrote:

Darren Slatten

unread,
Jun 1, 2013, 11:58:54 AM6/1/13
to duran...@googlegroups.com
What is the vision for the build step?

The short answer:

I don't actually have a vision for the build step. In fact, I've never even used .NET, NuGet, Node.js, or Mimosa. I'm assuming (hoping?) the folks who use those tools/frameworks can work with the structure I'm proposing and create the back-end support that meets their needs.

The long answer:

I approached this restructuring proposal from the perspective of someone who won't be using any back-end tools. I think it's important to establish a client-side-friendly structure first, and then configure the server tools around it. This strategy provides a couple of key benefits:

  1. It emphasizes that Durandal is a server-framework-agnostic, client-side JavaScript library. To maximize the growth/adoption of Durandal (which I'm assuming Rob thinks is important), we should avoid the implication that Durandal is dependent on (or was created specifically for) .NET or Node.js. While a significant percentage of current SPA developers might indeed use those frameworks, the percentage of web developers using them is much smaller. Durandal should appeal to all developers.
  2. It lowers the barrier to entry that typically discourages many web developers from trying something new. It does this by providing a frame of reference that is familiar to all web developers, designers, front-end developers, etc.: a typical web root directory. For example, if you already have a website (and basic experience with JavaScript or jQuery) but you've never created an SPA before, which of the following directory structures looks easier to use: this one or this one? For me personally, the only thing I recognize in Durandal's top-level directory is index.html--everything else looks scary and complicated. A more apples-to-apples comparison might be Darrendal's /Web folder vs. the contents of Durandal.zip, but even then my point is the same: Durandal doesn't look familiar or simple, and this discourages potential adopters.

Simply put, my vision for Durandal prioritizes client-side functionality over server-side tooling, but I'm hoping the former doesn't preclude the latter.



Would that include or exclude external libs?

I'm not sure what you mean (but I'll give it a shot). I think it makes the most sense if Durandal (referring to the git repo) includes the newest (tested, compatible) version of RequireJS, Text (loader plugin), jQuery, and Knockout...but...these should be directly under /lib, not under /lib/durandal. Since the location of each lib is centrally defined (in the RequireJS configuration), developers can easily upgrade/add/delete external libs without touching Durandal's core. In other words, external libs are included in the starter packages for convenience, but they're kept separate from Durandal's core (i.e., the AMD modules).

Did that answer your question?

Steve Gentile

unread,
Jun 1, 2013, 2:33:57 PM6/1/13
to Darren Slatten, duran...@googlegroups.com
Agree if others want to utilize their server side asset management strategy they can alter their requirejs structure, but out of the box durandal should use requirejs to load all it's dependencies.  Seems rather simple to setup and shim as I see in your fork, any chance this can be merged into durandal as the default setup Rob?

Ie I'm using durandal with rails which has its own pipeline but I want to use the require-rails gem to bootstrap durandal and the setup Darren has seems the least obtrusive.

Thanks!
Steve

Darren Slatten

unread,
Jun 1, 2013, 4:01:21 PM6/1/13
to r...@bluespire.com, duran...@googlegroups.com
Okay, I think I have a solution that will make everyone happy! Well...except maybe for short-term Rob, who would have to actually implement this solution. Long-term Rob will love it though, because I think it will pave the way for an explosive growth in Durandal's adoption rate.

The key concept in this solution is this:

Completely isolate Durandal from external libraries, server tools, and users' app code.

In practice, the solution would look like this:
  1. The name Durandal--according to the official definition--should only refer to a client-side library of AMD modules. Period. It's server-agnostic, framework-agnostic, and (ideally) even AMD loader-agnostic. It depends on jQuery and Knockout, but it does NOT include them--it does not include any other libs whatsoever. In other words, Durandal's top-level directory would look like this, but without the /amd directory. All the server-level stuff in the current repo would be (re)moved.
  2. The Durandal Starter Kits (or whatever you want to call them) should refer to Durandal + a set of files that allow developers to get up and running ASAP on a specific platform (e.g., .NET, Mimosa, manual, etc.). Each starter kit would include (1) Durandal, (2) the server-level files and build tools that are relevant to that platform, (3) the libs that Durandal depends on, using whatever directory structure makes sense for that specific platform, and (4) a copy of the Samples app (hopefully with a new name), which represents a functional user app.
  3. Each Starter Kit gets its own repository, but they all pull their Durandal files from the Durandal repo (and maybe pull their Sample app from a Sample repo?). This provides a much better upgrade path for everyone, because each Starter Kit can now be upgraded independently from Durandal (and vice versa). This allows Rob to work on Durandal without worrying about breaking Starter Kits (because it would be the Starter Kits' responsibilities to ensure compatibility before pulling in the changes to Durandal). This also allows Durandal to grow well beyond the .NET/Mimosa user base, because now anyone can create a Starter Kit for any platform.
  4. Starter Kits would each have the ability to pull in 3rd-party libs (including jQuery, RequireJS, etc.) from their respective repos.
  5. According to this solution, Darrendal's /Web directory would be analogous to the Manual Starter Kit (just like you suggested, Rob).

I do realize this solution goes way beyond the scope of "adding a feature for v2", but think about it, Rob: this system is going to be SO much easier to maintain in the long-run. And ultimately, it resolves both the "Pure AMD" issue and the "client-side vs. server-side" issue. And personally, I think Durandal is suffering from a bit of an identity crisis--this would resolve that too.  ;)



On Sat, Jun 1, 2013 at 12:29 PM, Rob Eisenberg <r...@bluespireconsulting.com> wrote:
Well...actually Durandal's projects are laid out exactly like .NET web apps are. Nuget specifies a particular structure, mimosa has a different arrangement. We will need out project organization to match the standard layouts that those developers are using. That said, those aren't the only options. As of the web site release this last week, I introduced the Durandal.zip which is just the raw starter kit files. Perhaps that is the place where your broader structural recommendations should live?


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.
 
 
--
Rob Eisenberg,
President - Blue Spire
www.durandaljs.com



--
Darren Slatten

Ω Alisson

unread,
Jun 1, 2013, 7:09:51 PM6/1/13
to Darren Slatten, r...@bluespire.com, duran...@googlegroups.com
+1 for this, I was scared of Durandal structure and this fork looks much more sane!

Rob Eisenberg

unread,
May 30, 2013, 1:28:06 PM5/30/13
to Tom McKearney, duran...@googlegroups.com
Actually your config sample goes a long way to making this happen...because now I don't have to go look that junk up. Does all that work with almond as well?


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
Jun 1, 2013, 1:29:38 PM6/1/13
to Darren Slatten, duran...@googlegroups.com
Well...actually Durandal's projects are laid out exactly like .NET web apps are. Nuget specifies a particular structure, mimosa has a different arrangement. We will need out project organization to match the standard layouts that those developers are using. That said, those aren't the only options. As of the web site release this last week, I introduced the Durandal.zip which is just the raw starter kit files. Perhaps that is the place where your broader structural recommendations should live?
On Sat, Jun 1, 2013 at 11:58 AM, Darren Slatten <darren...@gmail.com> wrote:
--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
Jun 1, 2013, 2:48:27 PM6/1/13
to Steve Gentile, Darren Slatten, duran...@googlegroups.com
Guys. We will probably do something like this. But, it is going to be the very last feature I put in 2.0. So, probably won't be able to merge this. Just hang tight.....


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
Jun 1, 2013, 4:11:14 PM6/1/13
to Darren Slatten, duran...@googlegroups.com
Those are all good ideas. There's something else that is being considered with respect to all this as well. Releasing durandal as a single JavaScript file: durandal.js. It would live along side other 3rd party libraries. Internally it would have all the modules defined, and once you hook it up with an AMD loader you would be able to require them the same as today. You would be responsible for configuring the loader for jQuery and KO so that that everything works correctly. Each starter kit would do that properly.

Rob Eisenberg

unread,
May 30, 2013, 1:16:52 PM5/30/13
to Tom McKearney, duran...@googlegroups.com
Just declaring the config block....


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
May 31, 2013, 9:40:15 AM5/31/13
to Maxime Séguin, duran...@googlegroups.com
There is a *strong* chance that 2.0 will move everything to AMD.


On Fri, May 31, 2013 at 9:26 AM, Maxime Séguin <maxime.for...@radio-canada.ca> wrote:
--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
Jun 1, 2013, 8:10:07 AM6/1/13
to Rainer Wittmann, duran...@googlegroups.com
Can you please move this into one of the tickets...it's really hard to track it here.


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
May 30, 2013, 3:39:51 PM5/30/13
to Darren Slatten, duran...@googlegroups.com
Can you create an issue for this and attach the provided link there. It is definitely something that is being considered...
--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Rob Eisenberg

unread,
May 30, 2013, 10:00:08 AM5/30/13
to Tom McKearney, duran...@googlegroups.com
Please feel free to do that. My main concern is making it easy for new developers, especially those with little to no require.js experience, to pick up and go...and to get their own third party library working. Perhaps it's just a matter of setting up Durandal that way and then providing some really simple, clear documentation. That's what I want to find out.


--
You received this message because you are subscribed to the Google Groups "DurandalJS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to durandaljs+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Darren Slatten

unread,
Jun 1, 2013, 10:46:26 PM6/1/13
to r...@bluespire.com, duran...@googlegroups.com
I think an all-inclusive durandal.js file is an excellent idea. That would fit perfectly with everything I just mentioned too.

I think you might even be able to code each Durandal module as a named function/object so that if a given module isn't called or referenced by the user app, then Uglify or Closure Compiler would detect this and completely remove it during the build. That way the folks using server tools wouldn't be forced to include the entire durandal.js file in their apps--only the modules they actually use would make it into the final output.

The only argument against durandal.js (that I can think of) is that it might actually perform worse in the browser, for the people who aren't using a build step. In other words, "synchronously" loading durandal.js via a single HTTP request might actually take longer than loading it asynchronously across multiple connections (6 connections in most browsers, I believe). This would depend on each user's server (e.g., how fast it can create new connections) and when/how their app loads in the browser (e.g., are any of the 6 connections already busy downloading other resources?).

Even if the single file were slightly slower in some cases, I'd still support the idea because of all the benefits it would provide. It would still be a huge net gain, in my opinion. I really hope you move forward with that, Rob.
--
Darren Slatten
Reply all
Reply to author
Forward
0 new messages