├── .bowerrc ├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .yo-rc.json ├── README.md ├── bower.json ├── coffeelint.json ├── e2e ├── .jshintrc ├── main.po.js └── main.spec.js ├── gulp ├── .jshintrc ├── build.js ├── e2e-tests.js ├── inject.js ├── markups.js ├── proxy.js ├── scripts.js ├── server.js ├── styles.js ├── unit-tests.js └── watch.js ├── gulpfile.js ├── karma.conf.js ├── package.json ├── protractor.conf.js └── src ├── app ├── components │ └── navbar │ │ ├── navbar.controller.coffee │ │ └── navbar.html ├── index.coffee ├── index.scss ├── main │ ├── main.controller.coffee │ ├── main.controller.spec.js │ └── main.html └── vendor.scss ├── assets └── images │ ├── angular.png │ ├── bootstrap.png │ ├── browsersync.png │ ├── coffeescript.png │ ├── gulp.png │ ├── jade.png │ ├── jasmine.png │ ├── karma.png │ ├── node-sass.png │ ├── protractor.png │ ├── ui-bootstrap.png │ └── yeoman.png ├── favicon.ico └── index.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Yeoman defaults 2 | node_modules/ 3 | bower_components/ 4 | .sass-cache/ 5 | .tmp/ 6 | dist/ 7 | 8 | # Others 9 | production/ 10 | 11 | 12 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globalstrict": true, 3 | "bitwise": true, 4 | "camelcase": true, 5 | "curly": true, 6 | "eqeqeq": true, 7 | "immed": true, 8 | "indent": 2, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "quotmark": "single", 13 | "regexp": true, 14 | "undef": true, 15 | "unused": true, 16 | "strict": true, 17 | "trailing": true, 18 | "smarttabs": true, 19 | "white": true, 20 | "validthis": true, 21 | "globals": { 22 | "angular": false, 23 | // Angular Mocks 24 | "inject": false, 25 | "module": false, 26 | // JASMINE 27 | "describe": false, 28 | "it": false, 29 | "before": false, 30 | "beforeEach": false, 31 | "after": false, 32 | "afterEach": false, 33 | "expect": false 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-gulp-angular": { 3 | "version": "0.11.0", 4 | "props": { 5 | "angularVersion": "~1.3.4", 6 | "angularModules": [ 7 | { 8 | "key": "animate", 9 | "module": "ngAnimate" 10 | }, 11 | { 12 | "key": "cookies", 13 | "module": "ngCookies" 14 | }, 15 | { 16 | "key": "touch", 17 | "module": "ngTouch" 18 | }, 19 | { 20 | "key": "sanitize", 21 | "module": "ngSanitize" 22 | } 23 | ], 24 | "jQuery": { 25 | "key": "jquery2" 26 | }, 27 | "resource": { 28 | "key": "none", 29 | "module": null 30 | }, 31 | "router": { 32 | "key": "ui-router", 33 | "module": "ui.router" 34 | }, 35 | "ui": { 36 | "key": "bootstrap", 37 | "module": null 38 | }, 39 | "bootstrapComponents": { 40 | "key": "ui-bootstrap", 41 | "module": "ui.bootstrap" 42 | }, 43 | "cssPreprocessor": { 44 | "key": "node-sass", 45 | "extension": "scss" 46 | }, 47 | "jsPreprocessor": { 48 | "key": "coffee", 49 | "extension": "coffee", 50 | "srcExtension": "coffee" 51 | }, 52 | "htmlPreprocessor": { 53 | "key": "jade", 54 | "extension": "jade" 55 | }, 56 | "foundationComponents": { 57 | "name": null, 58 | "version": null, 59 | "key": null, 60 | "module": null 61 | }, 62 | "paths": { 63 | "src": "src", 64 | "dist": "dist", 65 | "e2e": "e2e", 66 | "tmp": ".tmp" 67 | } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # advanced-gulp-example 2 | This repo is a tool for my Treehouse course on Gulp. 3 | 4 | This code was generated with the [generator-gulp-angular](https://github.com/Swiip/generator-gulp-angular) Yeoman Generator. 5 | 6 | ## Getting Started 7 | The site was already scaffolded with Yeoman, but you will need bower, so install yeoman globally: 8 | ``` 9 | npm install -g yeoman 10 | ``` 11 | You should have gulp installed globally as well: 12 | ``` 13 | npm install -g gulp 14 | ``` 15 | Clone this repo: 16 | ``` 17 | git clone 18 | ``` 19 | Install the project's node modules and bower components: 20 | ``` 21 | cd 22 | npm install 23 | bower install 24 | ``` 25 | 26 | Now you can run gulp commands! 27 | 28 | e.g.: 29 | ``` 30 | gulp serve 31 | gulp build 32 | #etc! 33 | ``` 34 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testApp", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "angular-animate": "~1.3.4", 6 | "angular-cookies": "~1.3.4", 7 | "angular-touch": "~1.3.4", 8 | "angular-sanitize": "~1.3.4", 9 | "jquery": "~2.1.1", 10 | "angular-ui-router": "~0.2.13", 11 | "bootstrap-sass-official": "~3.3.1", 12 | "angular-bootstrap": "~0.12.0", 13 | "angular": "~1.3.4" 14 | }, 15 | "devDependencies": { 16 | "angular-mocks": "~1.3.4" 17 | }, 18 | "resolutions": { 19 | "jquery": "~2.1.1", 20 | "angular": "~1.3.4" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /coffeelint.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrow_spacing": { 3 | "level": "ignore" 4 | }, 5 | "camel_case_classes": { 6 | "level": "error" 7 | }, 8 | "coffeescript_error": { 9 | "level": "error" 10 | }, 11 | "colon_assignment_spacing": { 12 | "level": "ignore", 13 | "spacing": { 14 | "left": 0, 15 | "right": 0 16 | } 17 | }, 18 | "cyclomatic_complexity": { 19 | "value": 10, 20 | "level": "ignore" 21 | }, 22 | "duplicate_key": { 23 | "level": "error" 24 | }, 25 | "empty_constructor_needs_parens": { 26 | "level": "ignore" 27 | }, 28 | "indentation": { 29 | "value": 2, 30 | "level": "error" 31 | }, 32 | "line_endings": { 33 | "level": "ignore", 34 | "value": "unix" 35 | }, 36 | "max_line_length": { 37 | "value": 150, 38 | "level": "error", 39 | "limitComments": true 40 | }, 41 | "missing_fat_arrows": { 42 | "level": "ignore" 43 | }, 44 | "newlines_after_classes": { 45 | "value": 3, 46 | "level": "ignore" 47 | }, 48 | "no_backticks": { 49 | "level": "error" 50 | }, 51 | "no_debugger": { 52 | "level": "warn" 53 | }, 54 | "no_empty_functions": { 55 | "level": "ignore" 56 | }, 57 | "no_empty_param_list": { 58 | "level": "ignore" 59 | }, 60 | "no_implicit_braces": { 61 | "level": "ignore", 62 | "strict": true 63 | }, 64 | "no_implicit_parens": { 65 | "strict": true, 66 | "level": "ignore" 67 | }, 68 | "no_interpolation_in_single_quotes": { 69 | "level": "ignore" 70 | }, 71 | "no_plusplus": { 72 | "level": "ignore" 73 | }, 74 | "no_stand_alone_at": { 75 | "level": "ignore" 76 | }, 77 | "no_tabs": { 78 | "level": "error" 79 | }, 80 | "no_throwing_strings": { 81 | "level": "error" 82 | }, 83 | "no_trailing_semicolons": { 84 | "level": "error" 85 | }, 86 | "no_trailing_whitespace": { 87 | "level": "error", 88 | "allowed_in_comments": false, 89 | "allowed_in_empty_lines": true 90 | }, 91 | "no_unnecessary_double_quotes": { 92 | "level": "ignore" 93 | }, 94 | "no_unnecessary_fat_arrows": { 95 | "level": "warn" 96 | }, 97 | "non_empty_constructor_needs_parens": { 98 | "level": "ignore" 99 | }, 100 | "prefer_english_operator": { 101 | "level": "ignore", 102 | "doubleNotLevel": "ignore" 103 | }, 104 | "space_operators": { 105 | "level": "ignore" 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /e2e/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "globals": { 4 | "browser": false, 5 | "element": false, 6 | "by": false, 7 | "$": false, 8 | "$$": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /e2e/main.po.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This file uses the Page Object pattern to define the main page for tests 3 | * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ 4 | */ 5 | 6 | 'use strict'; 7 | 8 | var MainPage = function() { 9 | this.jumbEl = element(by.css('.jumbotron')); 10 | this.h1El = this.jumbEl.element(by.css('h1')); 11 | this.imgEl = this.jumbEl.element(by.css('img')); 12 | this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in awesomeThings')); 13 | }; 14 | 15 | module.exports = new MainPage(); 16 | -------------------------------------------------------------------------------- /e2e/main.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('The main view', function () { 4 | var page; 5 | 6 | beforeEach(function () { 7 | browser.get('http://localhost:3000/index.html'); 8 | page = require('./main.po'); 9 | }); 10 | 11 | it('should include jumbotron with correct data', function() { 12 | expect(page.h1El.getText()).toBe('\'Allo, \'Allo!'); 13 | expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); 14 | expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); 15 | }); 16 | 17 | it('list more than 5 awesome things', function () { 18 | expect(page.thumbnailEls.count()).toBeGreaterThan(5); 19 | }); 20 | 21 | }); 22 | -------------------------------------------------------------------------------- /gulp/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../.jshintrc", 3 | "node": true 4 | } 5 | -------------------------------------------------------------------------------- /gulp/build.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')({ 6 | pattern: ['gulp-*', 'main-bower-files', 'uglify-save-license', 'del'] 7 | }); 8 | 9 | module.exports = function(options) { 10 | gulp.task('partials', ['markups'], function () { 11 | return gulp.src([ 12 | options.src + '/app/**/*.html', 13 | options.tmp + '/serve/app/**/*.html' 14 | ]) 15 | .pipe($.minifyHtml({ 16 | empty: true, 17 | spare: true, 18 | quotes: true 19 | })) 20 | .pipe($.angularTemplatecache('templateCacheHtml.js', { 21 | module: 'testApp', 22 | root: 'app' 23 | })) 24 | .pipe(gulp.dest(options.tmp + '/partials/')); 25 | }); 26 | 27 | gulp.task('html', ['inject', 'partials'], function () { 28 | var partialsInjectFile = gulp.src(options.tmp + '/partials/templateCacheHtml.js', { read: false }); 29 | var partialsInjectOptions = { 30 | starttag: '', 31 | ignorePath: options.tmp + '/partials', 32 | addRootSlash: false 33 | }; 34 | 35 | var htmlFilter = $.filter('*.html'); 36 | var jsFilter = $.filter('**/*.js'); 37 | var cssFilter = $.filter('**/*.css'); 38 | var assets; 39 | 40 | return gulp.src(options.tmp + '/serve/*.html') 41 | .pipe($.inject(partialsInjectFile, partialsInjectOptions)) 42 | .pipe(assets = $.useref.assets()) 43 | .pipe($.rev()) 44 | .pipe(jsFilter) 45 | .pipe($.ngAnnotate()) 46 | .pipe($.uglify({ preserveComments: $.uglifySaveLicense })).on('error', options.errorHandler('Uglify')) 47 | .pipe(jsFilter.restore()) 48 | .pipe(cssFilter) 49 | .pipe($.replace('../../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/', '../fonts/')) 50 | .pipe($.csso()) 51 | .pipe(cssFilter.restore()) 52 | .pipe(assets.restore()) 53 | .pipe($.useref()) 54 | .pipe($.revReplace()) 55 | .pipe(htmlFilter) 56 | .pipe($.minifyHtml({ 57 | empty: true, 58 | spare: true, 59 | quotes: true, 60 | conditionals: true 61 | })) 62 | .pipe(htmlFilter.restore()) 63 | .pipe(gulp.dest(options.dist + '/')) 64 | .pipe($.size({ title: options.dist + '/', showFiles: true })); 65 | }); 66 | 67 | // Only applies for fonts from bower dependencies 68 | // Custom fonts are handled by the "other" task 69 | gulp.task('fonts', function () { 70 | return gulp.src($.mainBowerFiles()) 71 | .pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}')) 72 | .pipe($.flatten()) 73 | .pipe(gulp.dest(options.dist + '/fonts/')); 74 | }); 75 | 76 | gulp.task('other', function () { 77 | return gulp.src([ 78 | options.src + '/**/*', 79 | '!' + options.src + '/**/*.{html,css,js,scss,coffee,jade}' 80 | ]) 81 | .pipe(gulp.dest(options.dist + '/')); 82 | }); 83 | 84 | gulp.task('clean', function (done) { 85 | $.del([options.dist + '/', options.tmp + '/'], done); 86 | }); 87 | 88 | gulp.task('build', ['html', 'fonts', 'other']); 89 | }; 90 | -------------------------------------------------------------------------------- /gulp/e2e-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var browserSync = require('browser-sync'); 8 | 9 | module.exports = function(options) { 10 | // Downloads the selenium webdriver 11 | gulp.task('webdriver-update', $.protractor.webdriver_update); 12 | 13 | gulp.task('webdriver-standalone', $.protractor.webdriver_standalone); 14 | 15 | function runProtractor (done) { 16 | 17 | gulp.src(options.e2e + '/**/*.js') 18 | .pipe($.protractor.protractor({ 19 | configFile: 'protractor.conf.js' 20 | })) 21 | .on('error', function (err) { 22 | // Make sure failed tests cause gulp to exit non-zero 23 | throw err; 24 | }) 25 | .on('end', function () { 26 | // Close browser sync server 27 | browserSync.exit(); 28 | done(); 29 | }); 30 | } 31 | 32 | gulp.task('protractor', ['protractor:src']); 33 | gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor); 34 | gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor); 35 | }; 36 | -------------------------------------------------------------------------------- /gulp/inject.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var wiredep = require('wiredep').stream; 8 | 9 | module.exports = function(options) { 10 | gulp.task('inject', ['scripts', 'styles'], function () { 11 | var injectStyles = gulp.src([ 12 | options.tmp + '/serve/app/**/*.css', 13 | '!' + options.tmp + '/serve/app/vendor.css' 14 | ], { read: false }); 15 | 16 | var injectScripts = gulp.src([ 17 | '{' + options.src + ',' + options.tmp + '/serve}/app/**/*.js', 18 | '!' + options.src + '/app/**/*.spec.js', 19 | '!' + options.src + '/app/**/*.mock.js' 20 | ]) 21 | .pipe($.angularFilesort()).on('error', options.errorHandler('AngularFilesort')); 22 | 23 | var injectOptions = { 24 | ignorePath: [options.src, options.tmp + '/serve'], 25 | addRootSlash: false 26 | }; 27 | 28 | return gulp.src(options.src + '/*.html') 29 | .pipe($.inject(injectStyles, injectOptions)) 30 | .pipe($.inject(injectScripts, injectOptions)) 31 | .pipe(wiredep(options.wiredep)) 32 | .pipe(gulp.dest(options.tmp + '/serve')); 33 | 34 | }); 35 | }; 36 | -------------------------------------------------------------------------------- /gulp/markups.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | 6 | var $ = require('gulp-load-plugins')(); 7 | 8 | module.exports = function(options) { 9 | gulp.task('markups', function() { 10 | function renameToHtml(path) { 11 | path.extname = '.html'; 12 | } 13 | 14 | return gulp.src(options.src + '/app/**/*.jade') 15 | .pipe($.consolidate('jade', { basedir: options.src, doctype: 'html', pretty: ' ' })).on('error', options.errorHandler('Jade')) 16 | .pipe($.rename(renameToHtml)) 17 | .pipe(gulp.dest(options.tmp + '/serve/app/')) 18 | .pipe(browserSync.reload({ stream: true })); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /gulp/proxy.js: -------------------------------------------------------------------------------- 1 | /*jshint unused:false */ 2 | 3 | /*************** 4 | 5 | This file allow to configure a proxy system plugged into BrowserSync 6 | in order to redirect backend requests while still serving and watching 7 | files from the web project 8 | 9 | IMPORTANT: The proxy is disabled by default. 10 | 11 | If you want to enable it, watch at the configuration options and finally 12 | change the `module.exports` at the end of the file 13 | 14 | ***************/ 15 | 16 | 'use strict'; 17 | 18 | var httpProxy = require('http-proxy'); 19 | var chalk = require('chalk'); 20 | 21 | /* 22 | * Location of your backend server 23 | */ 24 | var proxyTarget = 'http://server/context/'; 25 | 26 | var proxy = httpProxy.createProxyServer({ 27 | target: proxyTarget 28 | }); 29 | 30 | proxy.on('error', function(error, req, res) { 31 | res.writeHead(500, { 32 | 'Content-Type': 'text/plain' 33 | }); 34 | 35 | console.error(chalk.red('[Proxy]'), error); 36 | }); 37 | 38 | /* 39 | * The proxy middleware is an Express middleware added to BrowserSync to 40 | * handle backend request and proxy them to your backend. 41 | */ 42 | function proxyMiddleware(req, res, next) { 43 | /* 44 | * This test is the switch of each request to determine if the request is 45 | * for a static file to be handled by BrowserSync or a backend request to proxy. 46 | * 47 | * The existing test is a standard check on the files extensions but it may fail 48 | * for your needs. If you can, you could also check on a context in the url which 49 | * may be more reliable but can't be generic. 50 | */ 51 | if (/\.(html|css|js|png|jpg|jpeg|gif|ico|xml|rss|txt|eot|svg|ttf|woff|woff2|cur)(\?((r|v|rel|rev)=[\-\.\w]*)?)?$/.test(req.url)) { 52 | next(); 53 | } else { 54 | proxy.web(req, res); 55 | } 56 | } 57 | 58 | /* 59 | * This is where you activate or not your proxy. 60 | * 61 | * The first line activate if and the second one ignored it 62 | */ 63 | 64 | //module.exports = [proxyMiddleware]; 65 | module.exports = function() { 66 | return []; 67 | }; 68 | -------------------------------------------------------------------------------- /gulp/scripts.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | 6 | var $ = require('gulp-load-plugins')(); 7 | 8 | module.exports = function(options) { 9 | gulp.task('scripts', function () { 10 | return gulp.src(options.src + '/app/**/*.coffee') 11 | .pipe($.sourcemaps.init()) 12 | .pipe($.coffeelint()) 13 | .pipe($.coffeelint.reporter()) 14 | .pipe($.coffee()).on('error', options.errorHandler('CoffeeScript')) 15 | .pipe($.sourcemaps.write()) 16 | .pipe(gulp.dest(options.tmp + '/serve/app')) 17 | .pipe(browserSync.reload({ stream: true })) 18 | .pipe($.size()); 19 | }); 20 | }; 21 | -------------------------------------------------------------------------------- /gulp/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | var browserSyncSpa = require('browser-sync-spa'); 6 | 7 | var util = require('util'); 8 | 9 | var middleware = require('./proxy'); 10 | 11 | module.exports = function(options) { 12 | 13 | function browserSyncInit(baseDir, browser) { 14 | browser = browser === undefined ? 'default' : browser; 15 | 16 | var routes = null; 17 | if(baseDir === options.src || (util.isArray(baseDir) && baseDir.indexOf(options.src) !== -1)) { 18 | routes = { 19 | '/bower_components': 'bower_components' 20 | }; 21 | } 22 | 23 | var server = { 24 | baseDir: baseDir, 25 | routes: routes 26 | }; 27 | 28 | if(middleware.length > 0) { 29 | server.middleware = middleware; 30 | } 31 | 32 | browserSync.instance = browserSync.init({ 33 | startPath: '/', 34 | server: server, 35 | browser: browser 36 | }); 37 | } 38 | 39 | browserSync.use(browserSyncSpa({ 40 | selector: '[ng-app]'// Only needed for angular apps 41 | })); 42 | 43 | gulp.task('serve', ['watch'], function () { 44 | browserSyncInit([options.tmp + '/serve', options.src]); 45 | }); 46 | 47 | gulp.task('serve:dist', ['build'], function () { 48 | browserSyncInit(options.dist); 49 | }); 50 | 51 | gulp.task('serve:e2e', ['inject'], function () { 52 | browserSyncInit([options.tmp + '/serve', options.src], []); 53 | }); 54 | 55 | gulp.task('serve:e2e-dist', ['build'], function () { 56 | browserSyncInit(options.dist, []); 57 | }); 58 | }; 59 | -------------------------------------------------------------------------------- /gulp/styles.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | 6 | var $ = require('gulp-load-plugins')(); 7 | 8 | var wiredep = require('wiredep').stream; 9 | 10 | module.exports = function(options) { 11 | gulp.task('styles', function () { 12 | var sassOptions = { 13 | style: 'expanded' 14 | }; 15 | 16 | var injectFiles = gulp.src([ 17 | options.src + '/app/**/*.scss', 18 | '!' + options.src + '/app/index.scss', 19 | '!' + options.src + '/app/vendor.scss' 20 | ], { read: false }); 21 | 22 | var injectOptions = { 23 | transform: function(filePath) { 24 | filePath = filePath.replace(options.src + '/app/', ''); 25 | return '@import \'' + filePath + '\';'; 26 | }, 27 | starttag: '// injector', 28 | endtag: '// endinjector', 29 | addRootSlash: false 30 | }; 31 | 32 | var indexFilter = $.filter('index.scss'); 33 | var vendorFilter = $.filter('vendor.scss'); 34 | 35 | return gulp.src([ 36 | options.src + '/app/index.scss', 37 | options.src + '/app/vendor.scss' 38 | ]) 39 | .pipe(indexFilter) 40 | .pipe($.inject(injectFiles, injectOptions)) 41 | .pipe(indexFilter.restore()) 42 | .pipe(vendorFilter) 43 | .pipe(wiredep(options.wiredep)) 44 | .pipe(vendorFilter.restore()) 45 | .pipe($.sourcemaps.init()) 46 | .pipe($.sass(sassOptions)).on('error', options.errorHandler('Sass')) 47 | .pipe($.autoprefixer()).on('error', options.errorHandler('Autoprefixer')) 48 | .pipe($.sourcemaps.write()) 49 | .pipe(gulp.dest(options.tmp + '/serve/app/')) 50 | .pipe(browserSync.reload({ stream: true })); 51 | }); 52 | }; 53 | -------------------------------------------------------------------------------- /gulp/unit-tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | 5 | var $ = require('gulp-load-plugins')(); 6 | 7 | var wiredep = require('wiredep'); 8 | var karma = require('karma'); 9 | var concat = require('concat-stream'); 10 | var _ = require('lodash'); 11 | 12 | module.exports = function(options) { 13 | function listFiles(callback) { 14 | var wiredepOptions = _.extend({}, options.wiredep, { 15 | dependencies: true, 16 | devDependencies: true 17 | }); 18 | var bowerDeps = wiredep(wiredepOptions); 19 | 20 | var specFiles = [ 21 | options.src + '/**/*.spec.js', 22 | options.src + '/**/*.mock.js' 23 | ]; 24 | 25 | var htmlFiles = [ 26 | options.src + '/**/*.html' 27 | ]; 28 | 29 | var srcFiles = [ 30 | options.tmp + '/serve/app/**/*.js' 31 | ].concat(specFiles.map(function(file) { 32 | return '!' + file; 33 | })); 34 | 35 | 36 | gulp.src(srcFiles) 37 | .pipe($.angularFilesort()).on('error', options.errorHandler('AngularFilesort')) 38 | .pipe(concat(function(files) { 39 | callback(bowerDeps.js 40 | .concat(_.pluck(files, 'path')) 41 | .concat(htmlFiles) 42 | .concat(specFiles)); 43 | })); 44 | } 45 | 46 | function runTests (singleRun, done) { 47 | listFiles(function(files) { 48 | karma.server.start({ 49 | configFile: __dirname + '/../karma.conf.js', 50 | files: files, 51 | singleRun: singleRun, 52 | autoWatch: !singleRun 53 | }, done); 54 | }); 55 | } 56 | 57 | gulp.task('test', ['scripts'], function(done) { 58 | runTests(true, done); 59 | }); 60 | gulp.task('test:auto', ['watch'], function(done) { 61 | runTests(false, done); 62 | }); 63 | }; 64 | -------------------------------------------------------------------------------- /gulp/watch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var browserSync = require('browser-sync'); 5 | 6 | function isOnlyChange(event) { 7 | return event.type === 'changed'; 8 | } 9 | 10 | module.exports = function(options) { 11 | gulp.task('watch', ['markups', 'inject'], function () { 12 | 13 | gulp.watch([options.src + '/*.html', 'bower.json'], ['inject']); 14 | 15 | gulp.watch([ 16 | options.src + '/app/**/*.css', 17 | options.src + '/app/**/*.scss' 18 | ], function(event) { 19 | if(isOnlyChange(event)) { 20 | gulp.start('styles'); 21 | } else { 22 | gulp.start('inject'); 23 | } 24 | }); 25 | 26 | gulp.watch([ 27 | options.src + '/app/**/*.js', 28 | options.src + '/app/**/*.coffee' 29 | ], function(event) { 30 | if(isOnlyChange(event)) { 31 | gulp.start('scripts'); 32 | } else { 33 | gulp.start('inject'); 34 | } 35 | }); 36 | 37 | gulp.watch(options.src + '/app/**/*.jade', ['markups']); 38 | 39 | gulp.watch(options.src + '/app/**/*.html', function(event) { 40 | browserSync.reload(event.path); 41 | }); 42 | }); 43 | }; 44 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var gulp = require('gulp'); 4 | var gutil = require('gulp-util'); 5 | var wrench = require('wrench'); 6 | 7 | var options = { 8 | src: 'src', 9 | dist: 'dist', 10 | tmp: '.tmp', 11 | e2e: 'e2e', 12 | errorHandler: function(title) { 13 | return function(err) { 14 | gutil.log(gutil.colors.red('[' + title + ']'), err.toString()); 15 | this.emit('end'); 16 | }; 17 | }, 18 | wiredep: { 19 | directory: 'bower_components', 20 | exclude: [/bootstrap-sass-official\/.*\.js/, /bootstrap\.css/] 21 | } 22 | }; 23 | 24 | wrench.readdirSyncRecursive('./gulp').filter(function(file) { 25 | return (/\.(js|coffee)$/i).test(file); 26 | }).map(function(file) { 27 | require('./gulp/' + file)(options); 28 | }); 29 | 30 | gulp.task('default', ['clean'], function () { 31 | gulp.start('build'); 32 | }); 33 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = function(config) { 4 | 5 | var configuration = { 6 | autoWatch : false, 7 | 8 | frameworks: ['jasmine'], 9 | 10 | ngHtml2JsPreprocessor: { 11 | stripPrefix: 'src/', 12 | moduleName: 'gulpAngular' 13 | }, 14 | 15 | browsers : ['PhantomJS'], 16 | 17 | plugins : [ 18 | 'karma-phantomjs-launcher', 19 | 'karma-jasmine', 20 | 'karma-ng-html2js-preprocessor' 21 | ], 22 | 23 | preprocessors: { 24 | 'src/**/*.html': ['ng-html2js'] 25 | } 26 | }; 27 | 28 | // This block is needed to execute Chrome on Travis 29 | // If you ever plan to use Chrome and Travis, you can keep it 30 | // If not, you can safely remove it 31 | // https://github.com/karma-runner/karma/issues/1144#issuecomment-53633076 32 | if(configuration.browsers[0] === 'Chrome' && process.env.TRAVIS) { 33 | configuration.customLaunchers = { 34 | 'chrome-travis-ci': { 35 | base: 'Chrome', 36 | flags: ['--no-sandbox'] 37 | } 38 | }; 39 | configuration.browsers = ['chrome-travis-ci']; 40 | } 41 | 42 | config.set(configuration); 43 | }; 44 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testApp", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "scripts": { 6 | "test": "gulp test" 7 | }, 8 | "devDependencies": { 9 | "gulp": "~3.8.10", 10 | "gulp-autoprefixer": "~2.1.0", 11 | "gulp-angular-templatecache": "~1.5.0", 12 | "del": "~1.1.1", 13 | "lodash": "~3.2.0", 14 | "gulp-csso": "~1.0.0", 15 | "gulp-filter": "~2.0.2", 16 | "gulp-flatten": "~0.0.4", 17 | "gulp-jshint": "~1.9.0", 18 | "gulp-load-plugins": "~0.8.0", 19 | "gulp-size": "~1.2.0", 20 | "gulp-uglify": "~1.1.0", 21 | "gulp-useref": "~1.1.0", 22 | "gulp-util": "~3.0.2", 23 | "gulp-ng-annotate": "~0.5.2", 24 | "gulp-replace": "~0.5.0", 25 | "gulp-rename": "~1.2.0", 26 | "gulp-rev": "~3.0.1", 27 | "gulp-rev-replace": "~0.3.1", 28 | "gulp-minify-html": "~0.1.7", 29 | "gulp-inject": "~1.1.1", 30 | "gulp-protractor": "~0.0.12", 31 | "gulp-sourcemaps": "~1.3.0", 32 | "gulp-sass": "~1.3.0", 33 | "gulp-coffee": "~2.3.1", 34 | "gulp-coffeelint": "~0.4.0", 35 | "gulp-angular-filesort": "~1.0.4", 36 | "gulp-consolidate": "~0.1.2", 37 | "jade": "~1.8.1", 38 | "main-bower-files": "~2.5.0", 39 | "merge-stream": "~0.1.7", 40 | "jshint-stylish": "~1.0.0", 41 | "wiredep": "~2.2.0", 42 | "karma": "~0.12.31", 43 | "karma-jasmine": "~0.3.1", 44 | "karma-phantomjs-launcher": "~0.1.4", 45 | "karma-ng-html2js-preprocessor": "~0.1.2", 46 | "concat-stream": "~1.4.7", 47 | "require-dir": "~0.1.0", 48 | "browser-sync": "~2.1.4", 49 | "browser-sync-spa": "~1.0.2", 50 | "http-proxy": "~1.8.0", 51 | "chalk": "~0.5.1", 52 | "protractor": "~1.7.0", 53 | "uglify-save-license": "~0.4.1", 54 | "wrench": "~1.5.8" 55 | }, 56 | "engines": { 57 | "node": ">=0.10.0" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var paths = require('./.yo-rc.json')['generator-gulp-angular'].props.paths; 4 | 5 | // An example configuration file. 6 | exports.config = { 7 | // The address of a running selenium server. 8 | //seleniumAddress: 'http://localhost:4444/wd/hub', 9 | //seleniumServerJar: deprecated, this should be set on node_modules/protractor/config.json 10 | 11 | // Capabilities to be passed to the webdriver instance. 12 | capabilities: { 13 | 'browserName': 'chrome' 14 | }, 15 | 16 | // Spec patterns are relative to the current working directly when 17 | // protractor is called. 18 | specs: [paths.e2e + '/**/*.js'], 19 | 20 | // Options to be passed to Jasmine-node. 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /src/app/components/navbar/navbar.controller.coffee: -------------------------------------------------------------------------------- 1 | angular.module "testApp" 2 | .controller "NavbarCtrl", ($scope) -> 3 | $scope.date = new Date() 4 | -------------------------------------------------------------------------------- /src/app/components/navbar/navbar.html: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /src/app/index.coffee: -------------------------------------------------------------------------------- 1 | angular.module 'testApp', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ui.router', 'ui.bootstrap'] 2 | .config ($stateProvider, $urlRouterProvider) -> 3 | $stateProvider 4 | .state "home", 5 | url: "/", 6 | templateUrl: "app/main/main.html", 7 | controller: "MainCtrl" 8 | 9 | $urlRouterProvider.otherwise '/' 10 | 11 | -------------------------------------------------------------------------------- /src/app/index.scss: -------------------------------------------------------------------------------- 1 | .browsehappy { 2 | margin: 0.2em 0; 3 | background: #ccc; 4 | color: #000; 5 | padding: 0.2em 0; 6 | } 7 | 8 | .thumbnail { 9 | height: 200px; 10 | 11 | img.pull-right { 12 | width: 50px; 13 | } 14 | } 15 | 16 | /* Do not remove this comments bellow. It's the markers used by gulp-inject to inject 17 | all your sass files automatically */ 18 | // injector 19 | // endinjector 20 | -------------------------------------------------------------------------------- /src/app/main/main.controller.coffee: -------------------------------------------------------------------------------- 1 | angular.module "testApp" 2 | .controller "MainCtrl", ($scope) -> 3 | $scope.awesomeThings = [ 4 | { 5 | 'title': 'AngularJS', 6 | 'url': 'https://angularjs.org/', 7 | 'description': 'HTML enhanced for web apps!', 8 | 'logo': 'angular.png' 9 | }, 10 | { 11 | 'title': 'BrowserSync', 12 | 'url': 'http://browsersync.io/', 13 | 'description': 'Time-saving synchronised browser testing.', 14 | 'logo': 'browsersync.png' 15 | }, 16 | { 17 | 'title': 'GulpJS', 18 | 'url': 'http://gulpjs.com/', 19 | 'description': 'The streaming build system.', 20 | 'logo': 'gulp.png' 21 | }, 22 | { 23 | 'title': 'Jasmine', 24 | 'url': 'http://jasmine.github.io/', 25 | 'description': 'Behavior-Driven JavaScript.', 26 | 'logo': 'jasmine.png' 27 | }, 28 | { 29 | 'title': 'Karma', 30 | 'url': 'http://karma-runner.github.io/', 31 | 'description': 'Spectacular Test Runner for JavaScript.', 32 | 'logo': 'karma.png' 33 | }, 34 | { 35 | 'title': 'Protractor', 36 | 'url': 'https://github.com/angular/protractor', 37 | 'description': 'End to end test framework for AngularJS applications built on top of WebDriverJS.', 38 | 'logo': 'protractor.png' 39 | }, 40 | { 41 | 'title': 'Bootstrap', 42 | 'url': 'http://getbootstrap.com/', 43 | 'description': 'Bootstrap is the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.', 44 | 'logo': 'bootstrap.png' 45 | }, 46 | { 47 | 'title': 'Angular UI Bootstrap', 48 | 'url': 'http://angular-ui.github.io/bootstrap/', 49 | 'description': 'Bootstrap components written in pure AngularJS by the AngularUI Team.', 50 | 'logo': 'ui-bootstrap.png' 51 | }, 52 | { 53 | 'title': 'Sass (Node)', 54 | 'url': 'https://github.com/sass/node-sass', 55 | 'description': 'Node.js binding to libsass, the C version of the popular stylesheet preprocessor, Sass.', 56 | 'logo': 'node-sass.png' 57 | }, 58 | { 59 | 'title': 'CoffeeScript', 60 | 'url': 'http://coffeescript.org/', 61 | 'description': 'CoffeeScript, \'a little language that compiles into JavaScript\'.', 62 | 'logo': 'coffeescript.png' 63 | }, 64 | { 65 | 'key': 'jade', 66 | 'title': 'Jade', 67 | 'url': 'http://jade-lang.com/', 68 | 'description': 'Jade is a high performance template engine heavily influenced by Haml and implemented with JavaScript for node.', 69 | 'logo': 'jade.png' 70 | } 71 | ] 72 | angular.forEach $scope.awesomeThings, (awesomeThing) -> 73 | awesomeThing.rank = Math.random() 74 | -------------------------------------------------------------------------------- /src/app/main/main.controller.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('controllers', function(){ 4 | var scope; 5 | 6 | beforeEach(module('testApp')); 7 | 8 | beforeEach(inject(function($rootScope) { 9 | scope = $rootScope.$new(); 10 | })); 11 | 12 | it('should define more than 5 awesome things', inject(function($controller) { 13 | expect(scope.awesomeThings).toBeUndefined(); 14 | 15 | $controller('MainCtrl', { 16 | $scope: scope 17 | }); 18 | 19 | expect(angular.isArray(scope.awesomeThings)).toBeTruthy(); 20 | expect(scope.awesomeThings.length > 5).toBeTruthy(); 21 | })); 22 | }); 23 | -------------------------------------------------------------------------------- /src/app/main/main.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 |

'Allo, 'Allo!

7 |

8 | I'm Yeoman
9 | Always a pleasure scaffolding your apps. 10 |

11 |

Splendid!

12 |
13 | 14 |
15 |
16 |
17 | {{awesomeThing.title}} 18 |
19 |

{{awesomeThing.title}}

20 |

{{awesomeThing.description}}

21 |

{{awesomeThing.url}}

22 |
23 |
24 |
25 |
26 | 27 |
28 | 29 | 32 | 33 |
34 | -------------------------------------------------------------------------------- /src/app/vendor.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: "../../bower_components/bootstrap-sass-official/assets/fonts/bootstrap/"; 2 | 3 | /* Do not remove this comments bellow. It's the markers used by wiredep to inject 4 | sass dependencies when defined in the bower.json of your dependencies */ 5 | // bower:scss 6 | // endbower 7 | -------------------------------------------------------------------------------- /src/assets/images/angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/angular.png -------------------------------------------------------------------------------- /src/assets/images/bootstrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/bootstrap.png -------------------------------------------------------------------------------- /src/assets/images/browsersync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/browsersync.png -------------------------------------------------------------------------------- /src/assets/images/coffeescript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/coffeescript.png -------------------------------------------------------------------------------- /src/assets/images/gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/gulp.png -------------------------------------------------------------------------------- /src/assets/images/jade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/jade.png -------------------------------------------------------------------------------- /src/assets/images/jasmine.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/jasmine.png -------------------------------------------------------------------------------- /src/assets/images/karma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/karma.png -------------------------------------------------------------------------------- /src/assets/images/node-sass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/node-sass.png -------------------------------------------------------------------------------- /src/assets/images/protractor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/protractor.png -------------------------------------------------------------------------------- /src/assets/images/ui-bootstrap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/ui-bootstrap.png -------------------------------------------------------------------------------- /src/assets/images/yeoman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/assets/images/yeoman.png -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hdngr/advanced-gulp-example/ff139ce744adc559526187c25b14d9ce07decb9c/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | testApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 27 | 28 |
29 | 30 | 31 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | --------------------------------------------------------------------------------