{"id":36834,"date":"2016-04-29T04:34:49","date_gmt":"2016-04-29T11:34:49","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=6745"},"modified":"2016-04-29T04:34:49","modified_gmt":"2016-04-29T11:34:49","slug":"webforms-can-gulp-too-using-node-tools-with-asp-net-webforms","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/webforms-can-gulp-too-using-node-tools-with-asp-net-webforms\/","title":{"rendered":"WebForms can Gulp too &#8211; Using Node Tools with ASP.NET WebForms"},"content":{"rendered":"<p>Visual Studio 2015 brought a set of tools into the IDE from the Node environment that are great for web developers to use.\u00a0 Many folks who build JavaScript applications or single-page-applications were eager to see the introduction of these tools to Visual Studio.\u00a0 Can the tried and true ASP.NET Web Forms framework use Gulp, npm, bower, and the Task Runner Explorer?\u00a0 In this blog post, we&#8217;ll take a look at how we can replace the &#8216;out of the box&#8217; use of the Script Manager in a Web Forms app with these node-based tools.<\/p>\n<h2>Why Not Use ScriptBundles?<\/h2>\n<p>ScriptBundles and StyleBundles are a great tool that allow you to configure and deliver resources to your visitors in a compressed package to reduce or even eliminate extra requests to your web server.\u00a0 These features allow you to define a bundle of resources in an xml-based config file or configuration classes like BundleConfig.cs\u00a0 This approach, while easy to configure, requires the web service execute server-side code in order to configure and deliver these resources.\u00a0 The alternative approach described below, completes this work one time during the build process and delivers static files every time to the requestor.\u00a0 This approach will also prepare your assets for use on Cordova, WinJS, or ASP.NET Core where you don&#8217;t have the bundling capabilities.\u00a0 Finally, because we are using package managers to manage our scripts and styles, we can get new versions with fixes and features installed easily with the help of these tools.<\/p>\n<h2>Introducing npm, gulp, and bower<\/h2>\n<p><img decoding=\"async\" class=\"alignleft size-medium wp-image-6755\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/GulpBowerNpm-300x262-1.png\" alt=\"Gulp Bower Npm logos\" width=\"300\" height=\"262\" \/>These three tools provide the building blocks for browser-side coding in our application.\u00a0 Let&#8217;s take a quick look at each tool and what it does:<\/p>\n<ul>\n<li>npm is the <a href=\"http:\/\/npmjs.org\">Node Package Manager<\/a>.\u00a0 This is the NuGet equivalent in the Node platform and can install other Node tools and components, including the other two listed below.<\/li>\n<li><a href=\"http:\/\/bower.io\">Bower<\/a> is another package manager that delivers static content like CSS, Images, JavaScript, and Fonts.<\/li>\n<li><a href=\"http:\/\/gulpjs.com\/\">Gulp <\/a>is a task runner that can be used to &#8216;build&#8217; your browser-side resources for delivery to your visitors.\u00a0 It can be used to automate other tasks, but provides a great JavaScript-based framework and toolset to automate your repetitive tasks.<\/li>\n<\/ul>\n<p>This walk-through focuses on the default ASP.NET 4.6 template and converting those resources to use this acquisition and build mechanism.<\/p>\n<h2>Step 1 &#8211; Configure npm<\/h2>\n<p>Nope.. Step 1 is not install NodeJS, because if you&#8217;re using Visual Studio 2015 its already installed for you in C:Program Files (x86)Microsoft Visual Studio 14.0Common7IDEWeb ToolsExternal\u00a0\u00a0 We can move forward and start configuring the node package manager for our project.\u00a0 In the Visual Studio Solution Explorer window, Add a New Item to the base folder of your project, and choose npm Configuration File.\u00a0 You&#8217;ll probably notice that the other configuration files we&#8217;re going to use are in the list as well: Bower Configuration File and Gulp Configuration File.\u00a0 Go ahead and add those to your project as well.<\/p>\n<p>Starting with the package.json file, we can see that there isn&#8217;t a lot in the base file to start.\u00a0 Thanks to the intellisense features built into Visual Studio, we&#8217;re going to get some help in building out the list of devDependencies at the bottom of the file.<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/initialPackageJson.png\"><img decoding=\"async\" class=\"aligncenter wp-image-6765 size-full\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/initialPackageJson-1.png\" alt=\"initialPackageJson\" width=\"579\" height=\"278\" \/><\/a><\/p>\n<p>Inside of the devDependencies block, lets enter a JSON name-value pair for the gulp package.\u00a0 As you start typing &#8220;gulp&#8221;: the Visual Studio editor should begin showing some intellisense hints of the list of packages and versions available.\u00a0 Choose the latest version of Gulp, and lets also add references for the gulp-concat, gulp-cssmin, and gulp-uglify packages.\u00a0 My package.json file looks like this:<\/p>\n<p>You can now right-click on the package.json file in your solution explorer and choose to &#8216;Restore Packages&#8217; and Visual Studio will run the npm install command to acquire and make these packages available to you in a new &#8220;node_modules&#8221; folder.<\/p>\n<h2>Step 2 &#8211; Configuring Bower<\/h2>\n<p>Since we already added a bower.json template in the previous step, we work with that file to begin adding package references to match those that were installed by NuGet into our project.\u00a0 There are two ways to do this: right-click bower.json and open the bower package manager UI or you can edit the bower.json file by hand.\u00a0 In both scenarios, you need to add the bootstrap, jquery, modernizer, and respond packages to your configuration.\u00a0 In my bower.json file, I added the matching version numbers of these packages so that they match the default version numbers in the ASP.NET template:<\/p>\n<p>If you keyed in the package names like I did, you can perform a similar right-click action on the bower.json file to restore packages. This will create the bower_components folder in your project folder and fill it with the files from these packages.<\/p>\n<h2>Step 3 &#8211; Configure Bootstrap and My CSS with Gulp<\/h2>\n<p>Next, we need to write some JavaScript in the gulpfile.js file to dictate the tasks that need to be accomplished to build our client-side resources.\u00a0 The initial gulpfile starts with a line to require(&#8220;gulp&#8221;) and we will need to require those other gulp-* libraries that were referenced by npm.\u00a0\u00a0\u00a0 Those lines will look like the following:<\/p>\n<p><img decoding=\"async\" class=\"aligncenter size-full wp-image-6786\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/gulpFile1-1.png\" alt=\"Initial Gulp references\" width=\"484\" height=\"116\" \/><\/p>\n<p>Next, start writing the gulp task called &#8220;min-css&#8221; with the following content:<\/p>\n<p>The task is defined with the task method on the Gulp object, submitting a name for the task and an function that should be executed for this task. Each step of this task&#8217;s function is a call from the gulp object through a series of pipes.\u00a0 In Gulp, content is piped from one step to the next using the pipe function.\u00a0 The first steps on lines 14,15 grabs the contents of the Bootstrap fonts folder and copies it to the fonts folder in the project.\u00a0 The second step on lines 17,18 does the same thing with the JavaScript files for bootstrap.\u00a0 The final steps in lines 21-25 do some extra steps besides copying content. In this last step, the contents of the bootstrap.min.css file and the site.css file are to be processed.\u00a0 These two files are marked up in the src method as an array of strings and are then piped into the concat command.\u00a0 Concat will take the contents of the pipe and combine them into one file at the location submitted, in this case the Content\/site.min.css file.\u00a0 Those contents are then passed into the cssmin function which will optimized the content of the CSS files by eliminating spaces, tabs and comments.\u00a0 This makes it smaller for transport and easier to download 1 file than multiple files.\u00a0 The final method, gulp.dest indicates that the results of the cssmin operation should be written back to that site.min.css file. At this point, we can run this step in the Task Runner Explorer window in Visual Studio by right clicking on the &#8216;min-css&#8217; task on the left side and choosing Run. This will run the task in the extra window pane of the Task Runner Explorer, and you should quickly have Bootstrap configured with a minimized CSS stylesheet at site.min.css Step 4 &#8211; JavaScript Configuration The JavaScript processing is a little more involved than the CSS, but reuses some of the same tasks we just learned about.<\/p>\n<p>This time, we&#8217;re going to assemble a collection of these files into one JavaScript file.\u00a0 For each of these five steps,\u00a0 we&#8217;re going to move files into the Scripts folder.\u00a0 For the jQuery, Modernizr, and Respond libraries it\u2019s a straight copy into the Scripts folder.\u00a0 With the MSAjaxBundle and WebFormsBundle, we&#8217;re going to take some steps before copying.\u00a0 These two bundles are originally added to your project through NuGet packages and bring a significant number of JavaScript files to your project.\u00a0 Let&#8217;s do something to simplify that.<\/p>\n<p>Each of these steps for MSAjaxBundle and WebFormsBundle collects a group of JavaScript files by using a wildcard in the src function.\u00a0 They then pipe those contents into the concat function to make one big JavaScript file named MSAjax.min.js or WebForms.min.js accordingly.\u00a0 The contents of those files are then piped into the uglify function, a function that minifies JavaScript by eliminating spaces, comments, and reduces the name of variables in JavaScript to a single character.\u00a0 Finally, those contents are saved back to disk in the same way that our CSS was with the gulp.dest method.<\/p>\n<p>We can now run this js task in the Task Runner Explorer window and see it produce the five JavaScript files for our project:<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/TaskRunnerExplorer.png\"><img class=\"aligncenter size-mediumlarge wp-image-6795\" alt=\"TaskRunnerExplorer\" width=\"500\" height=\"208\" \/><\/a><\/p>\n<h2>\u00a0Step 5 &#8211; Update the Master page<\/h2>\n<p>In the Master page, you can remove all references to the bundles and replace them with direct references to the scripts and styles:<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2016\/04\/MasterPageUpdated.png\"><img class=\"aligncenter size-mediumlarge wp-image-6805\" alt=\"MasterPage Updated\" width=\"500\" height=\"260\" \/><\/a><\/p>\n<p>You can also remove the configuration of bundles in the App_StartBundleConfig.cs file to reduce some processing at application start up.<\/p>\n<p>This is nice, but what happens when I add more to that site CSS file?\u00a0 I need to re-run the min-css step, where ASP.NET would just recompile it each time.<\/p>\n<h2>Step 6 &#8211; Configure Gulp-Watch<\/h2>\n<p>You can configure gulp to watch files for an update and when that update occurs, trigger tasks to be processed.\u00a0 This feature can be activated with the watch method on the gulp object.\u00a0 I like to create a task called simply watch and have that task run in the background while I code.\u00a0 Here is the code for my watch task in this project:<\/p>\n<p>This method takes an array of file globs and an array of tasks to execute if it detects a change in any of the files referenced.\u00a0 Now, when I change my site.css file, the minified version is regenerated very quickly.\u00a0 The Task Runner Explorer makes this even easier to use, because I can bind my watch task to the &#8216;Project Open&#8217; event so that the tasks runs whenever I open this project.\u00a0 To enable this event binding, right-click on the &#8216;watch&#8217; task in the Task Runner Explorer and choose &#8220;Bindings &#8211; Project Open&#8221;<\/p>\n<h2>Summary<\/h2>\n<p>This is just the beginning of a journey into the Node toolset for ASP.NET web forms developers.\u00a0 There are many different ways to configure scripts and tasks to run against your project to automate many repetitive tasks.\u00a0 What are some of your favorite packages and tips for managing JavaScript, CSS, and other resources in your project?\u00a0 Let us know in the discussion area below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Visual Studio 2015 brought a set of tools into the IDE from the Node environment that are great for web developers to use.\u00a0 Many folks who build JavaScript applications or single-page-applications were eager to see the introduction of these tools to Visual Studio.\u00a0 Can the tried and true ASP.NET Web Forms framework use Gulp, npm, [&hellip;]<\/p>\n","protected":false},"author":405,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197],"tags":[7422,7511,7512,7513],"class_list":["post-36834","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","tag-asp-net-web-forms","tag-bower","tag-gulp","tag-npm"],"acf":[],"blog_post_summary":"<p>Visual Studio 2015 brought a set of tools into the IDE from the Node environment that are great for web developers to use.\u00a0 Many folks who build JavaScript applications or single-page-applications were eager to see the introduction of these tools to Visual Studio.\u00a0 Can the tried and true ASP.NET Web Forms framework use Gulp, npm, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36834","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/405"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=36834"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36834\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=36834"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=36834"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=36834"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}