{"id":11496,"date":"2016-03-29T16:15:55","date_gmt":"2016-03-29T13:15:55","guid":{"rendered":"http:\/\/www.webcodegeeks.com\/?p=11496"},"modified":"2017-12-19T16:38:38","modified_gmt":"2017-12-19T14:38:38","slug":"angularjs-mvc-tutorial-part-2-bower-sass-grunt","status":"publish","type":"post","link":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/","title":{"rendered":"AngularJS MVC Tutorial \u2013 Part 2 &#8211; Bower, SASS and Grunt"},"content":{"rendered":"<p>This example is the part 2 of my <strong>MVC tutorial with Angular<\/strong>. I strongly suggest you read the <a href=\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-1-project-setup\/\" target=\"_blank\">part 1<\/a> if you have not as it shows how to do the MVC part of the project.<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n&nbsp;<br \/>\n[ulp id=&#8217;LXJcMJZXSsqGXYW8&#8242;]<\/p>\n<div class=\"toc\">\n<h3>Table Of Contents<\/h3>\n<dl>\n<dt><a href=\"#introduction\">1. Introduction<\/a><\/dt>\n<dt><a href=\"#bower\">2. Bower integration<\/a><\/dt>\n<dd>\n<dl>\n<dt><a href=\"#installation\">2.1. Installation<\/a><\/dt>\n<dt><a href=\"#initializingAProject\">2.1. Initializing a project<\/a><\/dt>\n<\/dl>\n<\/dd>\n<dt><a href=\"#sass\">3. SASS<\/a><\/dt>\n<dt><a href=\"#grunt\">4. Grunt<\/a><\/dt>\n<dd>\n<dl>\n<dt><a href=\"#setup\">4.1. Setup<\/a><\/dt>\n<dt><a href=\"#gruntClean\">4.2. grunt-contrib-clean<\/a><\/dt>\n<dt><a href=\"#gruntSass\">4.3. grunt-contrib-sass<\/a><\/dt>\n<dt><a href=\"#gruntCssMin\">4.4. grunt-contrib-cssmin<\/a><\/dt>\n<dt><a href=\"#gruntQUnit\">4.5. grunt-contrib-qunit<\/a><\/dt>\n<dt><a href=\"#gruntCopy\">4.6. grunt-contrib-copy<\/a><\/dt>\n<dt><a href=\"#gruntUglify\">4.7. grunt-contrib-uglify<\/a><\/dt>\n<\/dl>\n<\/dd>\n<dt><a href=\"#conclusion\">5. Conclusion<\/a><\/dt>\n<dt><a href=\"#download\">6. Download<\/a><\/dt>\n<\/dl>\n<\/div>\n<h2><a name=\"introduction\"><\/a>1. Introduction<\/h2>\n<p>This part will show you how to integrate <strong>Bower<\/strong> for dependency management with <strong>Grunt<\/strong> for bundling.<\/p>\n<h2><a name=\"bower\"><\/a>2. Bower integration<\/h2>\n<h3><a name=\"installation\"><\/a>2.1. Installation<\/h3>\n<p><strong>Bower<\/strong> is a package manager. Just like NPM would do, it allows to manage the dependencies of your projects with a configuration file called <code>bower.json<\/code>. To install Bower, you will need to run the following npm command:<\/p>\n<pre class=\"brush:bash\">\r\nnpm install -g bower\r\n<\/pre>\n<p>This will install Bower globally in your environment, not your project:<\/p>\n<pre class=\"brush:bash\">\r\nC:\\Users\\MyUser\\AppData\\Roaming\\npm\\node_modules\\bower\r\n<\/pre>\n<p>By doing so, the Bower client will be available in the command line.<\/p>\n<h3><a name=\"initializingAProject\"><\/a>2.2. Initializing a project<\/h3>\n<p>The first thing you need to make your project Bower-ready is a <code>bower.json<\/code> file. This file contains metadata about your application like licence information, authors, application name, etc., but also contains the dependencies of your project.<\/p>\n<p>In order to create the <code>bower.json<\/code> file, you can search on the Internet to find what is needed in it. It simply is a JSON object with predefined properties. Here, I will show you how to use the interactive command line to create the JSON file. You need to go in your project folder, in a command prompt and type:<\/p>\n<pre class=\"brush:bash\">\r\nbower init\r\n<\/pre>\n<p>This command will launch Bower&#8217;s module creation wizard which will ask you a couple of questions.<\/p>\n<div class=\"tip\"><strong>Tip<\/strong><br \/>Depending on the command line tool you use, you might get an error saying <em>Register requires an interactive shell<\/em>. In this case, you will need to run <code>bower init --config.interactive<\/code>.<\/div>\n<p>Once you were guided through the initialization steps, you will get a <code>bower.json<\/code> file in the folder where you ran the <code>bower init<\/code> command.<\/p>\n<p><span style=\"text-decoration: underline\"><em>bower.json<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\n{\r\n    \"name\": \"AngularTutorial\",\r\n    \"authors\": [\r\n        \"Sylvain \"\r\n    ],\r\n    \"description\": \"Angular MVC architecture tutorial for WebCodeGeeks.com\",\r\n    \"main\": \"server.js\",\r\n    \"moduleType\": [],\r\n    \"keywords\": [\r\n        \"angular\",\r\n        \"tutorial\",\r\n        \"webcodegeeks\"\r\n    ],\r\n    \"license\": \"MIT\",\r\n    \"homepage\": \"www.webcodegeeks.com\",\r\n    \"private\": true\r\n}\r\n<\/pre>\n<p>Now that we are set up with Bower, we can start to add our project&#8217;s dependencies. For this example, I used <strong>Angular<\/strong> for the MVC part, <strong>Bootstrap<\/strong> as the CSS framework and <strong>JQuery SVG<\/strong> to draw crosses and circles, so we can add the dependencies using Bower&#8217;s command line, simply by typing:<\/p>\n<pre class=\"brush:bash\">\r\nbower install angular --save\r\nbower install bootstrap --save\r\nbower install jquery-svg --save\r\n<\/pre>\n<p>Here, the <code>--save<\/code> attribute tells Bower to include our dependencies in the <code>bower.json<\/code> file. It is a common practice to add the <code>bower_components<\/code> to your <code>.gitignore<\/code> or other versioning tool ignore files, so by adding the dependencies to the <code>bower.json<\/code> file will only require other developers to run:<\/p>\n<pre class=\"brush:bash\">bower install<\/pre>\n<p>Which will retrieve the dependencies automatically.<\/p>\n<h2><a name=\"sass\"><\/a>3. SASS<\/h2>\n<p><a href=\"http:\/\/sass-lang.com\/\" target=\"_blank\">SASS<\/a> is an extension to CSS. In my opinion, I don&#8217;t see why developers would not pick SASS over CSS as it brings to CSS what was missing before. As this is not a SASS tutorial, I will only show you how you can integrate SASS with Grunt. <\/p>\n<p>In the example attached to this post (see below), you will find in the <code>src<\/code> folder another one called <code>scss<\/code>. In there, a file named <code>tictactoe.scss<\/code> should be found.<\/p>\n<p><span style=\"text-decoration: underline\"><em>tictactoe.scss<\/em><\/span><\/p>\n<pre class=\"brush:css\">\r\n$darkBorder: 2px solid lightgray;\r\n\r\nbody {\r\n    padding-top: 75px;\r\n}\r\n\r\n.cell {\r\n    border: $darkBorder;\r\n}\r\n\r\n.grid {\r\n    border: $darkBorder;\r\n}\r\n\r\n.social-logo {\r\n    width: 10%;\r\n    height: 10%;\r\n}\r\n<\/pre>\n<p>This SASS file will get compiled into CSS by Grunt.<\/p>\n<h2><a name=\"grunt\"><\/a>4. Grunt<\/h2>\n<p><strong>Grunt<\/strong> is a tool that allows the developers to automate recurring tasks. It is commonly used to compile (minify, uglify, merge) your project&#8217;s JavaScript files. Here, I will show you how I used it to run my unit tests, compile the SASS files into CSS, minify the compiled CSS file, uglify, minify and copy the JS files into one project file, bundle (and clean) the application in a deployment-ready folder and copy Bower&#8217;s dependencies in the bundled application.<\/p>\n<h3><a name=\"setup\"><\/a>4.1. Setup<\/h3>\n<p>The first thing you need to install is obviously Grunt. In order to have it ready on your project, you need 3 things. First, the <code>grunt-cli<\/code> command line tool for Grunt, then Grunt dependencies into your project, and a Grunt file to be executed.<\/p>\n<p>To install Grunt, simply open a command line and type: <code>npm install -g grunt-cli<\/code>.<\/p>\n<p>This will make Grunt runnable form any folder using the command line. Then, you need to add the Grunt dependencies in your <code>package.json<\/code> file, in your project. Locate the file from the command line and type:<\/p>\n<pre class=\"brush:bash\">npm install grunt --save<\/pre>\n<p>The last thing you need is a <code>Gruntfile.js<\/code> file into your project. I personally put it beside the <code>package.json<\/code> and <code>bower.json<\/code> files. In this file, include the following code:<\/p>\n<p><span style=\"text-decoration:underline\">Gruntfile.js<\/span><\/p>\n<pre class=\"brush:js\">\r\nmodule.exports = function (grunt) {\r\n    grunt.initConfig({\r\n        \r\n    });\r\n\r\n    grunt.registerTask('default', []);\r\n}\r\n<\/pre>\n<p>The first this I want to bring your attention to is the function parameter <code>grunt<\/code>. This gives us the API to tell Grunt what to do. The second thing is the call to <code>initConfig()<\/code> which will hold the configuration for the different plugins that we will use. Finally, <code>registerTask()<\/code> tells Grunt which plugin to run in which order.<\/p>\n<p>Using the command line, navigate to the <code>Gruntfile.js<\/code> and type <code>grunt<\/code>. It should execute successfully.<\/p>\n<pre class=\"brush:bash; highlight:[3]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\n\r\nDone, without errors.\r\n<\/pre>\n<h3><a name=\"gruntClean\"><\/a>4.2. grunt-contrib-clean<\/h3>\n<p>This Grunt plugin allows to recursively delete a folder. I personally use it to delete the folder in which the application is bundled. First, you need to install it using npm:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-clean --save<\/pre>\n<p>Then, in the <code>Gruntfile.js<\/code>, you need to load the plugin by calling the <code>loadNpmTasks()<\/code> method:<\/p>\n<pre class=\"brush:bash\">grunt.loadNpmTasks('grunt-contrib-clean');<\/pre>\n<p>Put this little piece of code between the call to <code>initConfig()<\/code> and <code>registerTask()<\/code>. Now that it will be loaded, it needs to be executed. Still in the Grunt file, locate the call to <code>registerTask()<\/code> and add <code>clean<\/code> in the array (second parameter). This array should contain the plugins in the appropriated order. It should now look like:<\/p>\n<pre class=\"brush:bash\">grunt.registerTask('default', ['clean']);<\/pre>\n<p>The last thing we need to do is to define the configuration. This plugin has one of the simplest configuration, all you need is to add the following attribute to the object passed to <code>initConfig()<\/code>:<\/p>\n<pre class=\"brush:bash\">clean: [\"lib\/tictactoe\/build\"]<\/pre>\n<p>Now, if you create a <code>build<\/code> folder, you should see that it will get cleaned if you run Grunt. For reference, your <code>Gruntfile.js<\/code> should look like:<\/p>\n<p><span style=\"text-decoration: underline\">Gruntfile.js<\/span><\/p>\n<pre class=\"brush:js\">\r\nmodule.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"]\r\n    });\r\n\r\n    grunt.registerTask('default', ['clean']);\r\n}\r\n<\/pre>\n<p>You can test by executing <code>grunt<\/code> from the command line:<\/p>\n<pre class=\"brush:bash; highlight:[3]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 1 path cleaned.\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<h3><a name=\"gruntSass\"><\/a>4.3. grunt-contrib-sass<\/h3>\n<p>This plugin allows Grunt to execute <strong>SASS<\/strong> on specific paths to SCSS files. The resulting files are defined by the configuration object. As prerequisites, you need to install <a href=\"https:\/\/www.ruby-lang.org\/en\/\" target=\"_blank\">Ruby<\/a> and then use <code>gem<\/code> to install <code>sass<\/code> (see <a href=\"http:\/\/sass-lang.com\/install\" target=\"_blank\">instructions<\/a>). When those requirements are met, install the Grunt plugin by executing:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-sass --save<\/pre>\n<p>Then, load it in the <code>Gruntfile.js<\/code> and set it in the executed plugins:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.registerTask('default', ['clean', 'sass']);\r\n<\/pre>\n<p>Then you need to configure it. The simplest way, in my opinion, is to add all files manually. If you get to a point where you have too many files, you can use <a href=\"https:\/\/github.com\/gruntjs\/grunt-contrib-sass#compile-files-in-a-directory\" target=\"_black\">another way<\/a> of configuring the <code>sass<\/code> object by referring to <a href=\"https:\/\/github.com\/gruntjs\/grunt-contrib-sass#example-config\" target=\"_blank\">their documentation<\/a>.<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\n    sass: {\r\n        dist: {\r\n            files: {\r\n                'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n            } \r\n        }\r\n    }\r\n<\/pre>\n<p>Add this attribute to the object passed to the <code>initConfig()<\/code> method in the <code>Gruntfile.js<\/code>. The attribute <code>dist<\/code> is a target name. Then, you specify a <code>files<\/code> attribute to the <code>target<\/code> object which will contain the list of paths to SCSS files and their compilation destinations. Those paths are defined as attributes, where the attribute name is the destination file and the value is the source file.<\/p>\n<p>Your <code>Gruntfile.js<\/code> should now look like:<\/p>\n<p><span style=\"text-decoration:underline\"><em>Gruntfile.js<\/em><\/span><\/p>\n<pre class=\"brush:js\">module.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"],\r\n        sass: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n                } \r\n            }\r\n        }\r\n    });\r\n    \r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.loadNpmTasks('grunt-contrib-clean');\r\n    \r\n    grunt.registerTask('default', ['clean', 'sass']);\r\n}\r\n<\/pre>\n<p>By executing this file with Grunt&#8217;s command line client, you should get something like:<\/p>\n<pre class=\"brush:bash; highlight:[5,6,7]\">\r\nC:\\Users\\closy2\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 0 paths cleaned.\r\n\r\nRunning \"sass:dist\" (sass) task\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\closy2\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<h3><a name=\"gruntCssMin\"><\/a>4.4. grunt-contrib-cssmin<\/h3>\n<p>This plugin is used to minify (i.e.: remove all non-necessary characters) CSS files. Here, I also use it to move the compiled CSS file into the bundle folder. Install it by running:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-cssmin --save<\/pre>\n<p>Then, load the plugin and defined it as runnable:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\n    grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin']);\r\n<\/pre>\n<p>Regarding the configuration, the format is exactly the same as for the SASS plugin:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush: js\">\r\ncssmin: {\r\n    dist: {\r\n        files: {\r\n            'lib\/tictactoe\/build\/css\/tictactoe.min.css': 'lib\/tictactoe\/src\/css\/tictactoe.css'\r\n        }\r\n    }    \r\n}\r\n<\/pre>\n<p>Your grunt file should now look like:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js<\/em><\/span><\/p>\n<pre class=\"brush: js\">\r\nmodule.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"],\r\n        sass: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n                } \r\n            }\r\n        },\r\n        cssmin: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/build\/css\/tictactoe.min.css': 'lib\/tictactoe\/src\/css\/tictactoe.css'\r\n                }\r\n            }\r\n        }\r\n    });\r\n    \r\n    grunt.loadNpmTasks('grunt-contrib-clean');\r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n    \r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin']);\r\n}\r\n<\/pre>\n<p>And the execution should create a <code>tictactoe.min.css<\/code> in the <code>build<\/code> folder.<\/p>\n<pre class=\"brush:bash;highlight:[7,8,9,10]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 1 path cleaned.\r\n\r\nRunning \"sass:dist\" (sass) task\r\n\r\nRunning \"cssmin:dist\" (cssmin) task\r\n&gt;&gt; 1 file created. 218 B \u2192 93 B\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<h3><a name=\"gruntQUnit\"><\/a>4.5. grunt-contrib-qunit<\/h3>\n<p>Another useful thing with Grunt is that it can run our tests suite and stop the build if a test fails. As part of this example, I used <strong>QUnit<\/strong> to make my unit tests. Install the Grunt plugin for QUnit by running:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-qunit --save<\/pre>\n<p>Then, like any other plugin, we need to load it and add it to the <code>default<\/code> task like so:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\n    grunt.loadNpmTasks('grunt-contrib-qunit');\r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit']);\r\n<\/pre>\n<p>Regarding the configuration of the plugin, it is pretty simple to do. All you need is to define a target, as usual, and an array containing the list of the html files containing the QUnit code, like so:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\nqunit: {\r\n    dist: ['lib\/tictactoe\/test\/*.html']\r\n}\r\n<\/pre>\n<p>As you can see, it accepts the wildcard character <code>*<\/code>, meaning that all html files will be executed.<\/p>\n<p>Your <code>Gruntfile.js<\/code> should now look like this:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\nmodule.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"],\r\n        sass: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n                } \r\n            }\r\n        },\r\n        cssmin: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/build\/css\/tictactoe.min.css': 'lib\/tictactoe\/src\/css\/tictactoe.css'\r\n                }\r\n            }\r\n        },\r\n        qunit: {\r\n            dist: ['lib\/tictactoe\/test\/*.html']\r\n        }\r\n    });\r\n    \r\n    grunt.loadNpmTasks('grunt-contrib-clean');\r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n    grunt.loadNpmTasks('grunt-contrib-qunit');\r\n    \r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit']);\r\n}\r\n<\/pre>\n<p>When you execute the Grunt file, you will see that the tests suite was executed and that all tests passed:<\/p>\n<pre class=\"brush: bash;highlight:[10, 11, 12, 13, 14]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 1 path cleaned.\r\n\r\nRunning \"sass:dist\" (sass) task\r\n\r\nRunning \"cssmin:dist\" (cssmin) task\r\n&gt;&gt; 1 file created. 218 B \u2192 93 B\r\n\r\nRunning \"qunit:dist\" (qunit) task\r\nTesting lib\/tictactoe\/test\/tests.html .........................OK\r\n&gt;&gt; 25 assertions passed (124ms)\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<div class=\"tip\"><strong>Tip<\/strong><br \/>If you use any other test frameworks, you should be able to find a plugin for you. There is one for <a href=\"https:\/\/github.com\/gruntjs\/grunt-contrib-jasmine\" target=\"_blank\">Jasmine (grunt-contrib-jasmine)<\/a>, <a href=\"https:\/\/www.npmjs.com\/package\/grunt-mocha-test\" target=\"_blank\">Mocha (grunt-mocha-test)<\/a> and <a href=\"https:\/\/github.com\/teerapap\/grunt-protractor-runner\" target=\"_blank\">Protractor (grunt-protractor-runner)<\/a>.<\/div>\n<h3><a name=\"gruntCopy\"><\/a>4.6. grunt-contrib-copy<\/h3>\n<p>The <strong>copy<\/strong> plugin of Grunt does what it says, it copies files from one folder to another. There is a bunch of <a href=\"https:\/\/github.com\/gruntjs\/grunt-contrib-copy#usage-examples\" target=\"_blank\">usage options<\/a>, but I will show you a couple. First, you install the plugin using:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-copy --save<\/pre>\n<p>Again, you load this plugin using the same method as above:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\n    grunt.loadNpmTasks('grunt-contrib-copy');\r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit', 'copy']);\r\n<\/pre>\n<p>Then, for the configuration part, you will need to tell which files to move. In this example, I copy from the <code>src<\/code> folder to the <code>build<\/code> folder all the static files like views, Bower&#8217;s dependencies, images, etc..<\/p>\n<p>So first, in the configuration object passed to Grunt, you need to add an attribute for <code>copy<\/code> and define a target, then the list of files to copy are passed as an array of objects:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\ncopy: {\r\n    dist: {\r\n        files: [\r\n            {\r\n                expand: false, filter: 'isFile', \r\n                src: ['bower_dependencies\/angular\/angular.min.js'],\r\n                dest: 'lib\/tictactoe\/build\/js\/angular.min.js'\r\n            },\r\n            {\r\n                expand: false, filter: 'isFile', \r\n                src: ['bower_dependencies\/bootstrap\/dist\/css\/bootstrap.min.css'],\r\n                dest: 'lib\/tictactoe\/build\/css\/bootstrap.min.css'\r\n            },\r\n            {\r\n                expand: false, filter: 'isFile', \r\n                src: ['bower_dependencies\/jquery-svg\/jquery.svg.min.js'],\r\n                dest: 'lib\/tictactoe\/build\/js\/jquery.svg.min.js'\r\n            },\r\n            {\r\n                expand: false, filter: 'isFile', \r\n                src: ['bower_dependencies\/jquery-svg\/jquery.svg.css'],\r\n                dest: 'lib\/tictactoe\/build\/css\/jquery.svg.css'\r\n            },\r\n            {\r\n                expand: false, filter: 'isFile', \r\n                src: ['bower_dependencies\/jquery\/dist\/jquery.min.js'],\r\n                dest: 'lib\/tictactoe\/build\/js\/jquery.min.js'\r\n            },\r\n            {\r\n                expand: true, filter: 'isFile', \r\n                cwd: 'lib\/tictactoe\/src\/views\/',\r\n                src: ['**\/*.html'],\r\n                dest: 'lib\/tictactoe\/build'\r\n            },\r\n            {\r\n                expand: true, filter: 'isFile', \r\n                cwd: 'lib\/tictactoe\/src\/img\/',\r\n                src: ['*'],\r\n                dest: 'lib\/tictactoe\/build\/img\/'\r\n            }\r\n        ]\r\n    }\r\n}\r\n<\/pre>\n<p>Note that you can use the same syntax as the other plugins for file, that is a JSON object were the property name is the destination folder and the value is the source folder. I also want to bring you attention to lines 29-34 and 35-40. The first object has the <code>expand<\/code> attribute set to true and the <code>src<\/code> has wildcards characters <code>**\/*.html<\/code> meaning that all files and folders present in <code>cwd<\/code> (current working directory) will get copied in the destination folder recursively and by keeping the folder structure.<\/p>\n<p>The other object has <code>expand<\/code> set to false and the <code>cwd<\/code> attribute has only the wildcard character <code>*<\/code> which indicates it will only copy the first level of files.<\/p>\n<p>Your Grunt file should now look like:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\nmodule.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"],\r\n        sass: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n                } \r\n            }\r\n        },\r\n        cssmin: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/build\/css\/tictactoe.min.css': 'lib\/tictactoe\/src\/css\/tictactoe.css'\r\n                }\r\n            }\r\n        },\r\n        qunit: {\r\n            dist: ['lib\/tictactoe\/test\/*.html']\r\n        },\r\n        copy: {\r\n            dist: {\r\n                files: [\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/angular\/angular.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/angular.min.js'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/bootstrap\/dist\/css\/bootstrap.min.css'],\r\n                        dest: 'lib\/tictactoe\/build\/css\/bootstrap.min.css'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery-svg\/jquery.svg.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/jquery.svg.min.js'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery-svg\/jquery.svg.css'],\r\n                        dest: 'lib\/tictactoe\/build\/css\/jquery.svg.css'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery\/dist\/jquery.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/jquery.min.js'\r\n                    },\r\n                    {\r\n                        expand: true, filter: 'isFile', \r\n                        cwd: 'lib\/tictactoe\/src\/views\/',\r\n                        src: ['**\/*.html'],\r\n                        dest: 'lib\/tictactoe\/build'\r\n                    },\r\n                    {\r\n                        expand: true, filter: 'isFile', \r\n                        cwd: 'lib\/tictactoe\/src\/img\/',\r\n                        src: ['*'],\r\n                        dest: 'lib\/tictactoe\/build\/img\/'\r\n                    }\r\n                ]\r\n            }\r\n        }\r\n    });\r\n    \r\n    grunt.loadNpmTasks('grunt-contrib-clean');\r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n    grunt.loadNpmTasks('grunt-contrib-qunit');\r\n    grunt.loadNpmTasks('grunt-contrib-copy');\r\n    \r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit', 'copy']);\r\n}\r\n<\/pre>\n<p>If you then execute it with <code>grunt<\/code>, you should see that your files gets copied in the <code>build<\/code> folder.<\/p>\n<pre class=\"brush:bash;highlight:[14,15,16,17]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 1 path cleaned.\r\n\r\nRunning \"sass:dist\" (sass) task\r\n\r\nRunning \"cssmin:dist\" (cssmin) task\r\n&gt;&gt; 1 file created. 218 B \u2192 93 B\r\n\r\nRunning \"qunit:dist\" (qunit) task\r\nTesting lib\/tictactoe\/test\/tests.html .........................OK\r\n&gt;&gt; 25 assertions passed (250ms)\r\n\r\nRunning \"copy:dist\" (copy) task\r\nCopied 11 files\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<div class=\"tip\"><strong>Tip<\/strong><br \/>For Bower components, there is a plugin specially built for this called <a href=\"https:\/\/github.com\/timmywil\/grunt-bowercopy\" target=\"_blank\">grunt-bowercopy<\/a>.<\/div>\n<h3><a name=\"gruntUglify\"><\/a>4.7. grunt-contrib-uglify<\/h3>\n<p>The last but not the least plugin I want to show you is responsible for the minification of your JavaScript source files. It will merge the files into one single <code>.js<\/code> file, minify it (remove all whitespaces, change variable names and functions to one letter, etc.) and copy the resulting file where it&#8217;s needed.<\/p>\n<p>First, install the plugin using:<\/p>\n<pre class=\"brush:bash\">npm install grunt-contrib-uglify --save<\/pre>\n<p>Then you load it in the Grunt file (you know how now, don&#8217;t you!):<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js;\">\r\n    grunt.loadNpmTasks('grunt-contrib-uglify');\r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit', 'copy', 'uglify']);\r\n<\/pre>\n<p>For the configuration of the plugin, all you need to specify is a target and list of files is built where the attribute name is the destination path and the value is an array of paths in the include order:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js (partial)<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\nuglify: {\r\n    dist: {\r\n        files: {\r\n            'lib\/tictactoe\/build\/js\/tictactoe.min.js': [\r\n                'lib\/tictactoe\/src\/tictactoe.js',\r\n                'lib\/tictactoe\/src\/modules\/TicTacToe.js',\r\n                'lib\/tictactoe\/src\/services\/DrawingService.js',\r\n                'lib\/tictactoe\/src\/services\/TicTacToeService.js',\r\n                'lib\/tictactoe\/src\/controllers\/TicTacToeController.js',\r\n                'lib\/tictactoe\/src\/directives\/GridDirective.js'\r\n            ]\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>For the last time, this should be your <code>Gruntfile.js<\/code>:<\/p>\n<p><span style=\"text-decoration: underline\"><em>Gruntfile.js<\/em><\/span><\/p>\n<pre class=\"brush:js\">\r\nmodule.exports = function(grunt) {\r\n    grunt.initConfig({\r\n        clean: [\"lib\/tictactoe\/build\"],\r\n        sass: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/src\/css\/tictactoe.css': 'lib\/tictactoe\/src\/scss\/tictactoe.scss'\r\n                } \r\n            }\r\n        },\r\n        cssmin: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/build\/css\/tictactoe.min.css': 'lib\/tictactoe\/src\/css\/tictactoe.css'\r\n                }\r\n            }\r\n        },\r\n        qunit: {\r\n            dist: ['lib\/tictactoe\/test\/*.html']\r\n        },\r\n        copy: {\r\n            dist: {\r\n                files: [\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/angular\/angular.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/angular.min.js'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/bootstrap\/dist\/css\/bootstrap.min.css'],\r\n                        dest: 'lib\/tictactoe\/build\/css\/bootstrap.min.css'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery-svg\/jquery.svg.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/jquery.svg.min.js'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery-svg\/jquery.svg.css'],\r\n                        dest: 'lib\/tictactoe\/build\/css\/jquery.svg.css'\r\n                    },\r\n                    {\r\n                        expand: false, filter: 'isFile', \r\n                        src: ['bower_dependencies\/jquery\/dist\/jquery.min.js'],\r\n                        dest: 'lib\/tictactoe\/build\/js\/jquery.min.js'\r\n                    },\r\n                    {\r\n                        expand: true, filter: 'isFile', \r\n                        cwd: 'lib\/tictactoe\/src\/views\/',\r\n                        src: ['**\/*.html'],\r\n                        dest: 'lib\/tictactoe\/build'\r\n                    },\r\n                    {\r\n                        expand: true, filter: 'isFile', \r\n                        cwd: 'lib\/tictactoe\/src\/img\/',\r\n                        src: ['*'],\r\n                        dest: 'lib\/tictactoe\/build\/img\/'\r\n                    }\r\n                ]\r\n            }\r\n        },\r\n        uglify: {\r\n            dist: {\r\n                files: {\r\n                    'lib\/tictactoe\/build\/js\/tictactoe.min.js': [\r\n                        'lib\/tictactoe\/src\/tictactoe.js',\r\n                        'lib\/tictactoe\/src\/modules\/TicTacToe.js',\r\n                        'lib\/tictactoe\/src\/services\/DrawingService.js',\r\n                        'lib\/tictactoe\/src\/services\/TicTacToeService.js',\r\n                        'lib\/tictactoe\/src\/controllers\/TicTacToeController.js',\r\n                        'lib\/tictactoe\/src\/directives\/GridDirective.js'\r\n                    ]\r\n                }\r\n            }\r\n        }\r\n    });\r\n    \r\n    grunt.loadNpmTasks('grunt-contrib-clean');\r\n    grunt.loadNpmTasks('grunt-contrib-sass');\r\n    grunt.loadNpmTasks('grunt-contrib-cssmin');\r\n    grunt.loadNpmTasks('grunt-contrib-qunit');\r\n    grunt.loadNpmTasks('grunt-contrib-copy');\r\n    grunt.loadNpmTasks('grunt-contrib-uglify');\r\n    \r\n    grunt.registerTask('default', ['clean', 'sass', 'cssmin', 'qunit', 'copy', 'uglify']);\r\n}\r\n<\/pre>\n<p>And the execution result should be something like:<\/p>\n<pre class=\"brush:bash; highlight:[17,18,19,20,21]\">\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;grunt\r\nRunning \"clean:0\" (clean) task\r\n&gt;&gt; 1 path cleaned.\r\n\r\nRunning \"sass:dist\" (sass) task\r\n\r\nRunning \"cssmin:dist\" (cssmin) task\r\n&gt;&gt; 1 file created. 218 B \u2192 93 B\r\n\r\nRunning \"qunit:dist\" (qunit) task\r\nTesting lib\/tictactoe\/test\/tests.html .........................OK\r\n&gt;&gt; 25 assertions passed (250ms)\r\n\r\nRunning \"copy:dist\" (copy) task\r\nCopied 11 files\r\n\r\nRunning \"uglify:dist\" (uglify) task\r\nFile lib\/tictactoe\/build\/js\/tictactoe.min.js created: 8 kB \u2192 3.02 kB\r\n&gt;&gt; 1 file created.\r\n\r\nDone, without errors.\r\n\r\nC:\\Users\\MyUser\\Desktop\\AngularTutorial&gt;\r\n<\/pre>\n<h2><a name=\"conclusion\"><\/a>5. Conclusion<\/h2>\n<p>In this example, I showed you how to integrate <strong>Grunt<\/strong> with <strong>Bower<\/strong> to copy the dependencies in the bundle folder, I also showed you a couple of useful Grunt plugins, and I quickly showed you how to make Grunt build your <strong>SASS<\/strong> files.<\/p>\n<p>In the next part, I will show you how to connect this to a <strong>Node.js<\/strong> back end and how we can make this game work in multi-player.<\/p>\n<h2><a name=\"download\"><\/a>6. Download<\/h2>\n<p>This was the second part of AngularJS MVC Tutorial, about  Bower, SASS and Grunt.<\/p>\n<div class=\"download\"><strong>Download<\/strong><br \/>You can download the full source code of this example here: <strong><a href=\"http:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2016\/03\/TicTacToe.zip\">TicTacToe<\/a><\/strong><\/div>\n","protected":false},"excerpt":{"rendered":"<p>This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of the project. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [ulp id=&#8217;LXJcMJZXSsqGXYW8&#8242;] Table Of Contents 1. Introduction 2. Bower integration &hellip;<\/p>\n","protected":false},"author":107,"featured_media":912,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[25],"tags":[266,49,45,310],"class_list":["post-11496","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-angular-js","tag-angularjs","tag-bower","tag-grunt","tag-sass"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026<\/title>\n<meta name=\"description\" content=\"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026\" \/>\n<meta property=\"og:description\" content=\"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\" \/>\n<meta property=\"og:site_name\" content=\"Web Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webcodegeeks\" \/>\n<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/sylvain.cloutier.589\" \/>\n<meta property=\"article:published_time\" content=\"2016-03-29T13:15:55+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-12-19T14:38:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Sylvain Cloutier\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@Syl20TOS\" \/>\n<meta name=\"twitter:site\" content=\"@webcodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Sylvain Cloutier\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"17 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\"},\"author\":{\"name\":\"Sylvain Cloutier\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/1b11a7869645a6cadbee612bc8d792b6\"},\"headline\":\"AngularJS MVC Tutorial \u2013 Part 2 &#8211; Bower, SASS and Grunt\",\"datePublished\":\"2016-03-29T13:15:55+00:00\",\"dateModified\":\"2017-12-19T14:38:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\"},\"wordCount\":1912,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg\",\"keywords\":[\"angularjs\",\"Bower\",\"Grunt\",\"Sass\"],\"articleSection\":[\"Angular.js\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\",\"name\":\"AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026\",\"isPartOf\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg\",\"datePublished\":\"2016-03-29T13:15:55+00:00\",\"dateModified\":\"2017-12-19T14:38:38+00:00\",\"description\":\"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of\",\"breadcrumb\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.webcodegeeks.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JavaScript\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/javascript\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Angular.js\",\"item\":\"https:\/\/www.webcodegeeks.com\/category\/javascript\/angular-js\/\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"AngularJS MVC Tutorial \u2013 Part 2 &#8211; Bower, SASS and Grunt\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#website\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"name\":\"Web Code Geeks\",\"description\":\"Web Developers Resource Center\",\"publisher\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.webcodegeeks.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\/\/www.webcodegeeks.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"contentUrl\":\"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webcodegeeks\",\"https:\/\/x.com\/webcodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/1b11a7869645a6cadbee612bc8d792b6\",\"name\":\"Sylvain Cloutier\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/a99e21011060c21ac77758d81e774b6366e0408789fc4b44ad01771374984a19?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/a99e21011060c21ac77758d81e774b6366e0408789fc4b44ad01771374984a19?s=96&d=mm&r=g\",\"caption\":\"Sylvain Cloutier\"},\"description\":\"Sylvain has been programming in Java for the past 5 years, mainly in the aerospace industry, as a lead developer of complex web based aircraft wiring systems. He is also one of the organizers of the Java User Group of Quebec City and currently works as a Java developer consultant at CGI.\",\"sameAs\":[\"http:\/\/www.webcodegeeks.com\/\",\"https:\/\/www.facebook.com\/sylvain.cloutier.589\",\"https:\/\/www.linkedin.com\/profile\/view?id=AAIAAAqXUbIBPSDqY-HagpgyXDIxl55bHvAKjao\",\"https:\/\/x.com\/Syl20TOS\"],\"url\":\"https:\/\/www.webcodegeeks.com\/author\/sylvain-cloutier\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026","description":"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/","og_locale":"en_US","og_type":"article","og_title":"AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026","og_description":"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of","og_url":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/","og_site_name":"Web Code Geeks","article_publisher":"https:\/\/www.facebook.com\/webcodegeeks","article_author":"https:\/\/www.facebook.com\/sylvain.cloutier.589","article_published_time":"2016-03-29T13:15:55+00:00","article_modified_time":"2017-12-19T14:38:38+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg","type":"image\/jpeg"}],"author":"Sylvain Cloutier","twitter_card":"summary_large_image","twitter_creator":"@Syl20TOS","twitter_site":"@webcodegeeks","twitter_misc":{"Written by":"Sylvain Cloutier","Est. reading time":"17 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#article","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/"},"author":{"name":"Sylvain Cloutier","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/1b11a7869645a6cadbee612bc8d792b6"},"headline":"AngularJS MVC Tutorial \u2013 Part 2 &#8211; Bower, SASS and Grunt","datePublished":"2016-03-29T13:15:55+00:00","dateModified":"2017-12-19T14:38:38+00:00","mainEntityOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/"},"wordCount":1912,"commentCount":0,"publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg","keywords":["angularjs","Bower","Grunt","Sass"],"articleSection":["Angular.js"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/","url":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/","name":"AngularJS MVC Tutorial \u2013 Part 2 - Bower, SASS and Grunt - Web Code Geeks - 2026","isPartOf":{"@id":"https:\/\/www.webcodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage"},"image":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage"},"thumbnailUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg","datePublished":"2016-03-29T13:15:55+00:00","dateModified":"2017-12-19T14:38:38+00:00","description":"This example is the part 2 of my MVC tutorial with Angular. I strongly suggest you read the part 1 if you have not as it shows how to do the MVC part of","breadcrumb":{"@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#primaryimage","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2014\/10\/gruntjs-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.webcodegeeks.com\/javascript\/angular-js\/angularjs-mvc-tutorial-part-2-bower-sass-grunt\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.webcodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"JavaScript","item":"https:\/\/www.webcodegeeks.com\/category\/javascript\/"},{"@type":"ListItem","position":3,"name":"Angular.js","item":"https:\/\/www.webcodegeeks.com\/category\/javascript\/angular-js\/"},{"@type":"ListItem","position":4,"name":"AngularJS MVC Tutorial \u2013 Part 2 &#8211; Bower, SASS and Grunt"}]},{"@type":"WebSite","@id":"https:\/\/www.webcodegeeks.com\/#website","url":"https:\/\/www.webcodegeeks.com\/","name":"Web Code Geeks","description":"Web Developers Resource Center","publisher":{"@id":"https:\/\/www.webcodegeeks.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.webcodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.webcodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.webcodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.webcodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webcodegeeks","https:\/\/x.com\/webcodegeeks"]},{"@type":"Person","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/1b11a7869645a6cadbee612bc8d792b6","name":"Sylvain Cloutier","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.webcodegeeks.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/a99e21011060c21ac77758d81e774b6366e0408789fc4b44ad01771374984a19?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/a99e21011060c21ac77758d81e774b6366e0408789fc4b44ad01771374984a19?s=96&d=mm&r=g","caption":"Sylvain Cloutier"},"description":"Sylvain has been programming in Java for the past 5 years, mainly in the aerospace industry, as a lead developer of complex web based aircraft wiring systems. He is also one of the organizers of the Java User Group of Quebec City and currently works as a Java developer consultant at CGI.","sameAs":["http:\/\/www.webcodegeeks.com\/","https:\/\/www.facebook.com\/sylvain.cloutier.589","https:\/\/www.linkedin.com\/profile\/view?id=AAIAAAqXUbIBPSDqY-HagpgyXDIxl55bHvAKjao","https:\/\/x.com\/Syl20TOS"],"url":"https:\/\/www.webcodegeeks.com\/author\/sylvain-cloutier\/"}]}},"_links":{"self":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/11496","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/users\/107"}],"replies":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/comments?post=11496"}],"version-history":[{"count":0,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/posts\/11496\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media\/912"}],"wp:attachment":[{"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/media?parent=11496"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/categories?post=11496"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.webcodegeeks.com\/wp-json\/wp\/v2\/tags?post=11496"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}