As applications become richer and more complex, it becomes important to structure code so that it’s easy to refactor components independently. To understand how one piece of code depends upon another, developers turn to the best practices of modularity and encapsulation to structure code as a collection of small, reusable parts. RequireJS is a popular script loading library that makes it easy to make your JavaScript modular, dividing it into these reusable parts.
Visual Studio provides great JavaScript editor support for RequireJS, with IntelliSense that can discover the modules of your application and provide accurate suggestions. If you use TypeScript, there’s built-in support for modules to compile into JavaScript that works with RequireJS. This post walks you through using RequireJS in Visual Studio with either JavaScript or TypeScript.
To use the RequireJS support in Visual Studio, install Visual Studio 2013 Update 4 or later, or Visual Studio 2015 CTP 6 or later. To follow along, you can also download the source code for the sample app.
Configuring your project
Start by adding RequireJS to your project with the NuGet package manager. You can right click on the project to show the NuGet package manager, search for RequireJS, and install it.
If you’re working with an ASP.NET 5 project, reference the “requirejs” package using the Bower package manager. You can learn more about using Grunt and Bower in Visual Studio 2015 from the ASP.NET website.
Before using RequireJS in your code, you need to add a reference to it in your main HTML file (or .aspx, .cshtml, etc.).For my application, I’ve placed require.js into a Scripts/lib folder.
<script src=”/Scripts/lib/require.js”></script>
In an ASP.NET project, you also need to add a Scripts/_references.js file to tell Visual Studio what JS libraries to use for IntelliSense. In that file, add the following reference to require.js, it’s not necessary to add references to any other .js files that will be subsequently loaded using RequireJS.
/// <reference path=”/Scripts/lib/require.js” start-page=”/index.html” />
If you’re working in a project that uses a .jsproj extension, such as an Apache Cordova or Windows Store app project, you can skip this step. The JavaScript editor automatically finds the references in your .html files.
The start-page attribute is a new attribute used to configure RequireJS support. This setting tells Visual Studio which page should be treated as the start page; this has an effect on how RequireJS will compute relative file paths in your source code.
Using a module
When using RequireJS, your app becomes a series of modules with explicit dependencies defined between each module. At runtime, RequireJS dynamically loads these modules as needed.
When adding a reference to RequireJS in your HTML file, the common use pattern is to specify a .js file that represents the initial module to load and initialize the application. In the index.html file, reference require.js and tell it to start by loading an app.js file:
<script src=”/Scripts/lib/require.js” data-main=”/Scripts/app”></script>
The data-main attribute tells RequireJS what file to load first (the “.js” extension will be added automatically by RequireJS when the app is run). In app.js write any JavaScript code you want; you can even use the RequireJS require() function to load another module. Visual Studio shows me IntelliSense suggestions for RequireJS APIs as I type:
Using this require() function, you’ll load a services/photoService module that you’ll create next:
require([‘services/photoService’], function callback(photoService) {
});
This require() call tells RequireJS to load a services/photoService.js file and attach the results to the photoService parameter in the callback function. This code waits for the photoService.js file to load, as well as any modules it references, before the callback function is called.
In the services/photoService.js file, add the following code to define a RequireJS module that returns a single function that gets a list of images:
define(function (require) {
function getPhotoList() {
return [
‘/images/image1.png’,
‘/images/image2.png’
];
}
return {
getPhotoList: getPhotoList
}
})
Within the app.js file, we now see IntelliSense suggestions for the newly created photoService:
Configuring RequireJS
Often, you’ll want to modify the default RequireJS configuration to customize file paths for your application, making it easier to read the code. In this example, I use a specific version of the jQuery library, but I want to use shorthand in my code. I can do this using the RequireJS config() function to use the name “jquery” instead of the full path to where I have jquery installed (lib/jquery-2.1.3). I’ll add a Scriptsmain.js file to my application with the following source in it:
requirejs.config({
paths: {
jquery:‘lib/jquery-2.1.3’
}
})
require(‘app’);
In photoService.js, I can now refer to the jQuery library simply as jquery and use the .ajax() function to retrieve a list of photos from my server.
You can see the finished sample code in the PhotoBrowser sample app.
Using RequireJS with TypeScript
I’ve just shown how you can use RequireJS when building an application using JavaScript. Using TypeScript, I can build the same RequireJS application. Since version 1, the TypeScript compiler has built-in support to make this easy. When using TypeScript’s external module support with the AMD module target, the JavaScript generated by the TypeScript compiler is compatible with RequireJS.
For example, I can simplify the minimal code I need to define my photoService module from:
define([‘jquery’], function (jq) {
return {
getPhotoList: function () {
return jq.ajax(‘/photos.json’);
}
}
})
To:
In the PhotoBrowser sample, you’ll find a workingexample of a RequireJS application built with TypeScript.
Learn more
To learn more about setting up RequireJS for your JavaScript project, see the Customizing IntelliSense for RequireJS article on MSDN. For a complete “getting started” walkthrough, see the RequireJS project site. To learn about using TypeScript AMD modules with RequireJS, see the external module support documentation on the TypeScript website.
Looking ahead, module loading is going to become increasingly popular for JavaScript applications. Modules are a core part of the specification for the next version of JavaScript, ES2015 (formerly ES6). We’ll continue to improve support for developing modularized codebases in the future.
If you haven’t already, install Visual Studio 2013 Update 4 or later, or Visual Studio 2015 CTP 6, to get started with RequireJS and let us know how well it works for you by sending us a smile or frown. You can also add your votes for future module loader support or other JavaScript editor features on our UserVoice site.
Jordan Matthiesen, Program Manager, Visual Studio JavaScript tools team @JMatthiesen Jordan has been at Microsoft for 3 years, working on JavaScript tooling for client application developers. Prior to this, he worked for 14 years developing web applications and products using ASP.NET/C#, HTML, CSS, and lots and lots of JavaScript. |
0 comments