Question

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();
        }
    };
});
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top