views:

84

answers:

4

I am trying to figure the best way to manage my javascript code for my MVC project. A few pages of my site are very heavy with javascript for the user interface due to the workflow of the pages.

In order to make development and debugging easier I split all my javascript into four .js files, Initializations.js which has all the functions to handle any form of jquery control and field initializations, DataRetrieval.js which has all the functions to retrieve and display data via ajax, DataModification.js which has all the functions to send data modifications to the server via ajax, and Utilities.js which have utility functions to help out.

Structuring it this way has helped my development effort in not only the fact that I know which file contains a specific function based on what the function does, but it also keeps my javascript files smaller. It also helps in debugging because I can see the scripts right from chrome's debugger, choose which file and easily find the function I need to debug. From what I'm reading this also helps as most browsers can download multiple .js files simultaneously and thus load the page faster. This also makes it easier to minify at a later time.

The issue I am noticing is that using .js files I cannot embed C# code into them, as they aren't views. This means that all my URLs have to have magic strings for them (so if I change routes later I have to change all the URLs by hand) and I can't use constants I have setup in C# to make everything manageable across the board (if I change a constant, such as what integer means a project is unpublished, I have to search for all references in my javascript files and change them by hand, which can lead to bugs).

Now one possibility I thought of is to turn my javascript files into partial views. However, this still makes debugging the page in a web browser pretty complicated as the page's source code will be littered with javascript. This also makes it hard to minify the javascript at a later time.

So what other strategies can I use to manage my javascript and keep it in line with the c#/MVC portions of the site and not have to violate DRY when I need to make changes?

The web application portion of my site still has a lot of development to do so there is still much more javascript to write, and I want to come up with a strategy before things get out of hand more than they already are.

A: 

Keep your JS structured the way it is, but pass it the important stuff instead of using magic strings.

Write a HTML Helper to pass the minimum data possible to JS and use that in your Site.Master, e.g. Here's a really simplified example.

public MvcHtmlString ScriptData(this HtmlHelper helper)
{
    var scriptData = "window.Routing.ImportantRoute = '" + Url.Action("ActionName", "ControllerName") + "'; ";
    // etc.
    return MvcHtmlString.Create("<script type = 'text/javascript'>" + scriptData + "</script>");
}

This technique is nice because it tends to limit the amount you pass.

Craig Stuntz
A: 

What I've done, and it may not be the best way but it works for me, is I use an Asset Manager. Not trying to advertise, but I use Telerik's WebAssetManager in their MVC product. There's an open source Asset Manager that I used in the past that might work also found here:

http://weblogs.asp.net/rashid/archive/2009/05/02/script-and-css-management-in-asp-net-mvc-part-2.aspx

With that in place, I structure my Assets like so:

Assets\
        Scripts\
                 Shared\  <--Jquery etc
                 ControllerName\
                                ViewName\

        Css\
            CssStuffGoesHere.css

The master page, and the views specify what JavaScript files they need to make them work, and then the asset manager brings them all together and combines them with a version for cacheing. Like I said, I don't know if it's perfect, but it makes things pretty simple.

As far as dynamic variables inside of the js files. I simply declare a route that points to ~\Scripts\Dynamic.js which allows me to inject any dynamic variables into the JavaScript that I need.

Jeff Sheldon
+1  A: 

You should check out an application called Pithy: http://github.com/clearwavebuild/Pithy

I use it in my MVC application pretty exclusively. You create a master Pithy.js file like below:

 "print.css": [
    "~/static/css/print.css"
],

"login-page.css": [
    "~/static/css/pages/page_login.css"
],

"login-page.js": [
    "~/static/js/pages/cw.page-login.js"
],

"changePassword-page.css": [
    "~/static/css/pages/page_changepassword.css"
],

"changePassword-page.js": [
    "~/static/js/pages/page-changepassword.js"
],

"encounter-list.css": [
    "~/static/css/encounter-list/encounter-list.print.css",
    "~/static/css/encounter-list/encounter-list.table.css"
],

Then in your C# views, you can call:

    <%= Pithy.Javascript.Render("changePassword-page.js") %>

This will load all corresponding JS files with that tag, minify and compress them.

As far as getting C# variables into the files that I need, I do use partial views, but my partial view ONLY has variable declarations from C#, then normal JS files will reference those variables.

For example:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script type="text/javascript">
    var BehaviorReduction = {

};

BehaviorReduction.loadingImage = "<%= Url.Content(Links.Static.img.ajax_loader_gif) %>";
BehaviorReduction.behaviorOverviewUrl =  "<%=Url.Action(MVC.BehaviorReduction.RenderBehaviorOverview()) %>";
BehaviorReduction.addNewBehaviorUrl = "<%=Url.Action(MVC.BehaviorReduction.AddNewBehavior()) %>";
</script>

Then:

<asp:Content runat="server" ID="Content3" ContentPlaceHolderID="JavaScript">
    <% Html.RenderPartial(MVC.BehaviorReduction.Views.BehaviorReductionJavascript);%>
    <%= Pithy.Javascript.Render("BehaviorReduction.js")%>
</asp:Content>

This whole process has made things very easy for us to manage our javascript. It stays clean, minified and compress for production releases and in development we can make sure that the files are NEVER cached which saves some headaches.

Climber104
A: 

In the end I'm going to go with the solution linked to by Uvita in the comments (this post). So far it seems to be working well, it allows me to perform minification as well as it lets me easily keep my javascript organized the same way I keep my views organized. All in all it seems the cleanest method to both asset management and MVC integration into my javascript files.

KallDrexx
Be careful with this fully dynamic approach to JavaScript output and minification. It may work early in a project, but serving "static" resources in this way can create unnecessary load on your server and reduce your future ability to optimize with CDNs (if needed). It's generally a "safer" and more scalable approach to use the "initVariables" approach described in the linked thread and by Zeus above.
Todd
Wouldn't caching take care of the server load issue (Most cases I will be using this is for routing URLs and project-wide constant values, thus I only need the javascript generated once really. As for CDNs, if I was switching to use a CDN I would have to change the src tags anyway, so I can still generate the javascript files, place them on a CDN and point my `<src>` tags to the CDN.
KallDrexx