1

I have followed this question to get started using RequireJS as well as the RequireJS jQuery Docs. I have not been able to find how to reuse packages in a single file or how to structure the file itself. The following code works as expected and displays the text on the page. The first part of the javascript is automatically created see this question for more details.

The part that I am concerned with is the AMDSpecs.js init method. This seems counterproductive to the AMD specs. If this is the case, do I need to call a require each time I need jQuery? I hope I am explaining what I mean, please ask if you need more information.

HTML

<div id="output"></div>

Javascript

<script src="/MVCTesting/Scripts/ThirdParty/RequireJS/require.js"></script>
<script type="text/javascript">
     require( [ "/MVCTesting/Scripts/AMD/core.js" ], function() {
     require( ["jquery", "/MVCTesting/Scripts/AMD/views/jquery/AMDSpecs.js"],                 
        function($, pm) {
           if (pm != undefined && pm.init) {
              pm.init($);
           }
        });
     });
</script>

/*AMDSpecs.js*/
define(function () {
    //Do setup work here

    return {
        $: undefined,
        setupEvents: function () {
            $("#output").text("jQuery is working!");
        },
        init: function ($) {
            this.$ = $;

            require(["Views/JQuery/AMDSpecs"], function (specs) {
                specs.setupEvents();
            });
        }
    };
});

UPDATE

Here is my working solution after Donald's answer with all code. Note, I still need to include the .js in the module name, but this simplifies the process a lot.

HtmlExtension.cs

    /// <summary>
    /// An Html helper for Require.js
    /// </summary>
    /// <param name="helper"></param>
    /// <param name="module">Location of the main.js file.</param>
    /// <returns></returns>
    public static MvcHtmlString RequireJS(this HtmlHelper helper, string module)
    {
        const string jsLocation = "Scripts/AMD/";

        //Don't build require string if there is not an amd script
        if (!File.Exists(helper.ViewContext.HttpContext.Server.MapPath(
                    GetAbsolutePath(Path.Combine(jsLocation, module + ".js")))))
        {
            return null;
        }

        var require = new StringBuilder();

        require.AppendLine("    require( [\"" + GetAbsolutePath(jsLocation + module + ".js") + "\"], function(pm) {");
        require.AppendLine("        if (pm != undefined && pm.init) {");
        require.AppendLine("            pm.init();");
        require.AppendLine("        }");
        require.AppendLine("    });");

        return new MvcHtmlString(require.ToString());
    }

    /// <summary>
    /// Convert the path to work in IIS for MVC
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    private static string GetAbsolutePath(string path)
    {
        return VirtualPathUtility.ToAbsolute("~/" + path);
    }

    /// <summary>
    /// Create the include for RequireJS based on the current page
    /// </summary>
    /// <param name="helper"></param>
    /// <returns></returns>
    public static MvcHtmlString ViewSpecificRequireJS(this HtmlHelper helper)
    {
        var action = helper.ViewContext.RouteData.Values["action"];
        var controller = helper.ViewContext.RouteData.Values["controller"];

        return helper.RequireJS(string.Format("views/{0}/{1}", controller, action));
    }

_Layout.cshtml (MVCTesting is my project name)

<script data-main="/MVCTesting/Scripts/AMD/core.js" src="~/Scripts/ThirdParty/RequireJS/require.js"></script>

AMDSpecs.js

define(["jquery"], function ($) {
    //Do setup work here

    return {
        setupEvents: function () {
            $("#output").text("jQuery is working!");
        },
        init: function () {
            this.setupEvents();
        }
    };
});
Community
  • 1
  • 1
JabberwockyDecompiler
  • 3,318
  • 2
  • 42
  • 54

1 Answers1

2

No, you're not doing it quite correctly. You're "main" JavaScript file, defined by the data-main attribute of the (one and only) <script> tag, should kick off the app. All other JavaScript files should represent "modules," that is, collections of functionality that relate to specific purposes.

Note that I don't understand what your app is doing, so hopefully the following example at least gets you started.

1. Load the main script:

<script data-main="main" src="/MVCTesting/Scripts/ThirdParty/RequireJS/require.js"></script>

2. "main.js" kicks off the app:

require(["AMDSpecs"], function(specs) {
  specs.init();
});

3. Break up your scripts into individual files representative of "modules". In this case, your "AMDSpecs" is a module:

/* AMDSpecs.js */

define(["jquery"], function($) {
  // do setup work here

  return {
    setupEvents: function() {
      $("#output").text("jQuery is working!");
    },
    init: function() {
      this.setupEvents();
    }
  };

});

Note that it isn't helpful to embed require calls within require calls unless there is a reason to conditional or lazily load a script.

P.S. Don't use the ".js" extension when requiring scripts -- that is done automatically by RequireJS.

Donald T
  • 10,234
  • 17
  • 63
  • 91
  • [Ahh, lightbulb](http://savorthesweetlife.files.wordpress.com/2012/07/lightbulb1-despicableme.jpg). That makes much more sense in the AMDSpecs. I will also add the data-main, I did that with a single page setup and it worked well, I followed [this blog](http://www.novanet.no/no/blog/yngve-bakken-nilsen/dates/2013/6/making-requirejs-play-nice-with-aspnet-mvc/) to get it to work with MVC. Not to say that is correct ;). – JabberwockyDecompiler Jan 24 '14 at 15:10
  • I mentioned in my update that I needed to add the .js. I found in the api this paragraph. `RequireJS also assumes by default that all dependencies are scripts, so it does not expect to see a trailing ".js" suffix on module IDs. RequireJS will automatically add it when translating the module ID to a path....` That is certainly what they tell you to do, and was very confusing at first. On single pages I must do that. But I had to add the extension with MVC. – JabberwockyDecompiler Jan 24 '14 at 15:59
  • It's suspicious that you need to specify a ".js" extension. That was a pitfall for me early on, because if I included it, the script would *not* be loaded. – Donald T Jan 31 '14 at 17:47