Build Single Page Apps – Part 6 – JavaScript Modules and Italian Food | John Papa

John Papa

Evangelist on the loose

Build Single Page Apps – Part 6 – JavaScript Modules and Italian Food

...

SPA’s are apps too. And as such when creating a SPA you will find yourself writing code to get data, push data, handle validation, change tracking, storing data locally, presenting data, and so much more. All of these roles could be written in a scattered manner across the app, but that causes redundancy, low code re-use and a readability and maintenance headache. And for you pattern folks (like me) it also violates DRY and SRP.

So what do we do? Make more, smaller code files that each handle one specific job.

You can get the details on how I use this approach in my upcoming Pluralsight course titled “Building Single Page Apps (SPA) with HTML5, ASP.NET Web API, Knockout and jQuery”. It’s T-minus 2 weeks before it’s due to be completed … so it’s getting close!

You can catch up on the previous posts in this series here:

More on the Code Camper SPA

Part 1 – The Story Begins (What is the Code Camper SPA?)

Part 2 – Client Technologies

Part 3 – Server Technologies (the Data Layer)

Part 4 – Serving JSON with ASP.NET Web API

Part 5 – HTML 5 and ASP.NET Web Optimization

Part 6 – JavaScript Modules

Part 7 – MVVM and KnockoutJS

Part 8 – Data Services on the Client

Part 9 – Navigation, Transitions, Storage and Messaging

Part 10 – Saving, Change Tracking, and Commanding

Part 11 – Responsive Design and Mobility

 

Spaghetti to Ravioli

I get ideas that pop in my head quickly and then they often leave just as quickly. So it’s important for me to get them written in code before I lose that thought. Because of this, I write code in iterations. I write it, test it, refactor it, test it, refactor it, and so on.

Pass 1: Toss the Spaghetti Against the Wall

The first pass of my code is rarely the best or most elegant, but it gets the job done. If I stopped here, I’d leave a code smell behind and have a lot of intermingled code that nobody would enjoy maintaining and would be impossible to test or expand upon.

Pass 2: Tasting the Spaghetti

Then I refine the code for all use cases. This is where I make sure it handles the roles that the code needs to handle. It’s better code, but still has a lot of duplication and ugliness.

Pass 3: Introducing Ravioli

Finally, I refactor it to be more maintainable. This is where I optimize the code, shorten it, create extension methods, service classes, and apply DRY and SRP.

Spaghetti Example

Let’s look at an extremely oversimplified and crude example. Below is an example of JavaScript code that displays a message. We could use this code throughout our app to display messages. However it explicitly hard codes the message to display, hard codes the jquery to do it, and if you wanted to change how it works you’d have to search all of your code to find it and replace it. Not very reusable and likely to have typos.

$('#messagebox').text('Welcome to Code Camp, John');

We could wrap this in a function, and that would help. But then what if other files want to use it? Then we need to make sure it is loaded in time. We could put it in its own module, and then it would be more reusable. Then we could make it use a custom message, but maybe a better solution is to tell it how to get the message. For that we could tell it to go talk to a module to get the message.

Again, this is an overly simplified example … but it is easily applicable to larger code issues.

Ravioli Example

Below is an example of a JavaScript module called alerter. It’s job is to display a message. It doesn’t know what message it will display, because that’s not its job. For that it depend upon jQuery and another module called a dataservice. Notice that the module uses a define statement to identify:

  1. The ID of the module
  2. The dependencies
  3. The factory for the module

image

This code has a few advantages our first spaghetti example did not:

  1. This ‘alerter’ module can be loaded as needed (using RequireJS)
  2. It is self-sufficient since it defines the dependencies up top (jQuery and dataservice). RequireJS will go out and find those modules and load them first, before the alerter is cranked up. How nice!
  3. The alerter doesn’t know how to go get the message, it defers that to the dataservice. So alert just “alerts” the user … which is its job.
  4. Using this code all over our app is as simple as saying

alerter.showMessage()

RequireJS

In my course I use RequireJS to handle the dependency resolution for my modules. RequireJS helps:

  1. Defines modules
  2. Resolve module dependencies
  3. Load scripts in the proper order (and asynchronously)

It does much more, too … but the reason I like using RequireJS is that it helps define a structure to the modules in my JavaScript apps that I otherwise would not have.

Want More?

In my course I go deeper on this concept and show how modularity can make it much easier to manage a SPA as it grows. I include several examples and as a bonus, here is a quick introductory sample using modularity and RequireJS on github that I wrote to help explain it. I call it kis-requirejs-demo for “Keep It Simple RequireJS Demo”

It’s part of a Visual Studio 2012 RTM solution, so you will need that to run it as is. Or you can pull the HTML and JavaScript out yourself and use another tool.

tags: javascript patterns pluralsight requirejs SPA
  • Jeff O’Connell

    John, fyi, the link back to your post 5 is broken in case someone else hasn’t notified you of it.

  • john

    Jeff – Thanks. I fixed the bit.ly link.

  • http://www.ibub.hu összehasonlítás

    really cool, step by step tutorial. thanks to Morning Brew for the link.

  • Al

    John, your course could not come at a better time. Are you still expecting to have this up on Pluralsight by early September?

  • john

    Al – Thanks for the comment. Yes, the course is on track for Sep 1 +/-.

  • http://mickdelaney.com mick

    you dont mention how you plan to optimize the requirejs modules your creating.
    are you going to use r.js in a build script?

  • Ray

    John, I am watching your course and it is so helpful for me .
    I am just wondering the reason why you used RequireJS in the CodeCamper source code, I mean, you used asp.net bundling to load all the scripts. What is the role of RequireJS in the CodeCamper?

  • john

    Hi Ray,
    Thanks, I am glad you like the course. Without RequireJS the modules would have to be executed and available in a specific order. So it handles that dependency resolution for me. I don’t use it’s optimization, as you noticed, but to me the more important part is knowing that when I need module X and it requires module Y and it in turn requires module Z that they will be loaded in the proper order and I do not have tto worry about that.

  • Ray

    Thanks John, as long as I use asp.net mvc, your idea makes sense.

  • Ray

    One more question, John.
    As you mentioned, if role of the require.js in the codecamper is only for dependency resolution, why do you pass some external libraries to the modules, for example, knockout, jquery, underscore and so on.
    Shouldn’t it handle dependencies only for among app scripts, not for external libraries?

  • john

    Ray,
    Some external libraries will put themselves in the global scope, which means you could avoid making them dependencies. However, some of them see require.js and will then use it instead of making a global variable. For example, Knockout will do this so if you do not “pass it in” then you can’t use ko.
    However, more importantly to me, it makes it easier to see which things each module depends on.

    • Ray

      let me take an example, what if I need to use jquery ui library in the modules, how to config?
      Congratulate new blog.

  • http://www.dubebe.com teoman

    really nice tutorial, these tips&tricks helps a lot to how to plan, optimize and test our web/mobile apps!

    We are on follow, thanks a lot!

  • Al

    Hi John,

    I have quick question about the main.js file. Why does the loadPluginsAndBoot function use “requirejs” while the boot function just uses “require”? What is the difference?

    Thanks,

    Al

  • StrandedPirate

    Was going through the course and noticed that you rendered the core javascript bundles to the page rather than let require.js do this for you. Is there any advantage to letting require.js handle this? I went down this path which is essentially loading certain things in sequence. (not sure if javascript snippets below will be allowed through..)

    // layout page snippet

    var _rootUrls = {
    jquery: “@Scripts.Url(“~/bundles/jquery”).ToString().Replace(“.js”, “”)”,
    jqueryplugins: “@Scripts.Url(“~/bundles/jqueryplugins”).ToString().Replace(“.js”, “”)”,
    knockout: “@Scripts.Url(“~/bundles/knockout”).ToString().Replace(“.js”, “”)”,
    knockoutplugins: “@Scripts.Url(“~/bundles/knockoutplugins”).ToString().Replace(“.js”, “”)”,
    backoffice: “@Scripts.Url(“~/bundles/backoffice”)”,
    kendoui: “@Scripts.Url(“~/bundles/kendoui”).ToString().Replace(“.js”, “”)”
    };

    // main.js snippet

    require.config({
    paths: {
    jquery: _rootUrls.jquery,
    jqueryplugins: _rootUrls.jqueryplugins,
    knockout: _rootUrls.knockout,
    knockoutplugins: _rootUrls.knockoutplugins,
    backoffice: _rootUrls.backoffice,
    kendoui: _rootUrls.kendoui
    },
    waitSeconds: 15
    });

    // load scripts in a specific order
    require([“jquery”],
    function (jquery) {
    console.info(“jquery is loaded”);
    require([“jqueryplugins”],
    function (jqueryplugins) {
    console.info(“jqueryplugins are loaded”);
    require([“knockout”],
    function (ko) {
    console.info(“knockout is loaded”);
    // here we put ko back into the global namespace
    window.ko = ko;
    require([“knockoutplugins”],
    function (ko) {
    console.info(“knockoutplugins are loaded”);
    loadEverythingElse();
    }
    );
    }
    );
    }
    );
    }
    );

  • Michael Duberstein

    Hi John,
    I am taking your SPA course on pluralsight.
    I can’t find the ModularDemo in the course materials.
    I notified their support today, just wanted to let you know in hopes to get a faster resolution.
    Thank you.

  • Jeff M

    Hey John.

    TypeScript doesn’t support non-anonymous define statements. Is it trivial to remove the module names from CodeCamper? Do you have to optimize with require.js?

    Any insight here would be great. Thanks for your fantastic Pluralsight presentation.

    Jeff

  • Rayk

    John, thanks for the info here.
    In general, how ‘big’ can a SPA be? Is this technique limited to only small apps like Code Camper? We have a good size application we are looking at converting from Windows Forms to the web. Looking at different technologies, this is looking like the best option. But we won’t be able to preload all the data and views. We will preload a dashboard style page, and then load the other views as necessary. Do you know of any articles or web sites that describe this technique a little more?

    Thanks, Rayk

    • John

      Hi Rayk – With any technology I recommend appraoching the app from a modular point of view. Think of it as many small apps working together serving distinct business functions that , when put together, form a larger business need. That, and building a modular framework that scales well are key. You can certanly do thus by hand. Or you can use a framework like angularjs, ember or durandal. All 3 overlap in some areas, but are very different in others, so they are not exactly the same. But where they meet is in providing a framework for building these types of web apps. I am a big fan of durandaljs.

      I agree that you dont want to preload all views and viewmodels for a larger app. Loading the dashboard, lookups, and any data and views needed right away are a good plan. Then load the rest just in time and on demand. You can use external templates, require.js and its text plugin, or use some of the frameworks I mentioned to help with it. For example, Durandaljs uses require.js and the text plugin to dynamically and asyncly load modules (both html and js). I’m currently working on a course that shows how to use this.

      I’d also like to add that BreezeJS has come a long way in the past year. If you write a SPA by hand and then use Breeze, you will easily see how much it saves you. It scales well and offers a lot of great rich data features for the client. I highly recommend looking at the combination of Knockout, Breeze and Durandal.

      Hope this helps.

%d bloggers like this: