├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── app ├── USAGE ├── index.js └── templates │ ├── 404.html │ ├── _package.json │ ├── bower.json │ ├── bowerrc │ ├── editorconfig │ ├── favicon.ico │ ├── gitattributes │ ├── gitignore │ ├── gulpfile.js │ ├── htaccess │ ├── index.html │ ├── jshintrc │ ├── main.css │ ├── main.scss │ └── robots.txt ├── contributing.md ├── package.json └── test ├── app_slug.js ├── gulp_file.js ├── sass_feature.js └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # 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 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | test/gulp-file 3 | test/sass 4 | test/slug 5 | temp/ 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | .editorconfig 3 | .travis.yml 4 | .jshintrc 5 | .gitattributes 6 | contributing.md 7 | test 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Niall O'Brien 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Web app generator [![Build Status](https://secure.travis-ci.org/yeoman/generator-gulp-webapp.svg?branch=master)](http://travis-ci.org/yeoman/generator-gulp-webapp) 2 | 3 | [Yeoman](http://yeoman.io) generator that scaffolds out a front-end web app using [Gulp](http://gulpjs.com/) for the build process. 4 | 5 | ## No longer maintained 6 | I no longer maintain this project as I simply don't use Twitter Bootstrap anymore. But please, feel free to fork and modify/improve what's here. Thanks. 7 | 8 | ## Features 9 | 10 | * Built-in preview server with BrowserSync *(new)* 11 | * CSS Autoprefixing *(new)* 12 | * Automagically compile Sass (via libsass) *(new)* 13 | * Automagically lint your scripts 14 | * Awesome Image Optimization (via OptiPNG, pngquant, jpegtran and gifsicle) 15 | * Automagically wire-up dependencies installed with [Bower](http://bower.io) (when `gulp watch` or `gulp wiredep`) 16 | * TODO: Mocha Unit Testing with PhantomJS 17 | * TODO: Optional - Leaner Modernizr builds *(new)* 18 | 19 | 20 | ## Getting Started 21 | 22 | - Install: `npm install -g generator-gulp-bootstrap` 23 | - Run: `yo gulp-bootstrap` 24 | - Run `gulp` for building and `gulp watch` for preview 25 | 26 | 27 | #### Third-Party Dependencies 28 | 29 | *(HTML/CSS/JS/Images/etc)* 30 | 31 | To install dependencies, run `bower install depName --save` to get the files, then add a `script` or `style` tag to your `index.html` or an other appropriate place. 32 | 33 | ## Options 34 | 35 | * `--skip-install` 36 | 37 | Skips the automatic execution of `bower` and `npm` after scaffolding has finished. 38 | 39 | * `--test-framework=` 40 | 41 | Defaults to `mocha`. Can be switched for another supported testing framework like `jasmine`. 42 | 43 | 44 | ## License 45 | 46 | [BSD license](http://opensource.org/licenses/bsd-license.php) 47 | -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new basic front-end web application. 3 | 4 | Options: 5 | Bootstrap: Include Bootstrap for Sass 6 | 7 | Example: 8 | yo gulp-webapp [--coffee] 9 | 10 | This will create: 11 | gulpfile.js: Configuration for the task runner. 12 | bower.json: Front-end packages installed by bower. 13 | package.json: Development packages installed by npm. 14 | 15 | app/: Your application files. 16 | test/: Unit tests for your application. 17 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var fs = require('fs'); 3 | var util = require('util'); 4 | var path = require('path'); 5 | var spawn = require('child_process').spawn; 6 | var yeoman = require('yeoman-generator'); 7 | var chalk = require('chalk'); 8 | var wiredep = require('wiredep'); 9 | 10 | var AppGenerator = module.exports = function Appgenerator(args, options, config) { 11 | yeoman.generators.Base.apply(this, arguments); 12 | 13 | // setup the test-framework property, gulpfile template will need this 14 | this.testFramework = options['test-framework'] || 'mocha'; 15 | 16 | // for hooks to resolve on mocha by default 17 | options['test-framework'] = this.testFramework; 18 | 19 | // resolved to mocha by default (could be switched to jasmine for instance) 20 | this.hookFor('test-framework', { 21 | as: 'app', 22 | options: { 23 | options: { 24 | 'skip-install': options['skip-install-message'], 25 | 'skip-message': options['skip-install'] 26 | } 27 | } 28 | }); 29 | 30 | this.options = options; 31 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 32 | }; 33 | 34 | util.inherits(AppGenerator, yeoman.generators.Base); 35 | 36 | AppGenerator.prototype.askFor = function askFor() { 37 | var cb = this.async(); 38 | 39 | // welcome message 40 | if (!this.options['skip-welcome-message']) { 41 | console.log(this.yeoman); 42 | console.log(chalk.magenta('Out of the box I include HTML5 Boilerplate, jQuery, and a gulpfile.js to build your app.')); 43 | } 44 | 45 | var prompts = [{ 46 | type: 'checkbox', 47 | name: 'features', 48 | message: 'What more would you like?', 49 | choices: [{ 50 | name: 'Bootstrap', 51 | value: 'includeBootstrap', 52 | checked: true 53 | }, { 54 | name: 'Modernizr', 55 | value: 'includeModernizr', 56 | checked: true 57 | }] 58 | }]; 59 | 60 | this.prompt(prompts, function (answers) { 61 | var features = answers.features; 62 | 63 | var hasFeature = function (feat) { 64 | return features.indexOf(feat) !== -1; 65 | } 66 | 67 | // manually deal with the response, get back and store the results. 68 | // we change a bit this way of doing to automatically do this in the self.prompt() method. 69 | this.includeBootstrap = hasFeature('includeBootstrap'); 70 | this.includeModernizr = hasFeature('includeModernizr'); 71 | 72 | cb(); 73 | }.bind(this)); 74 | }; 75 | 76 | AppGenerator.prototype.gulpfile = function () { 77 | this.template('gulpfile.js'); 78 | }; 79 | 80 | AppGenerator.prototype.packageJSON = function () { 81 | this.template('_package.json', 'package.json'); 82 | }; 83 | 84 | AppGenerator.prototype.git = function () { 85 | this.copy('gitignore', '.gitignore'); 86 | this.copy('gitattributes', '.gitattributes'); 87 | }; 88 | 89 | AppGenerator.prototype.bower = function () { 90 | this.copy('bowerrc', '.bowerrc'); 91 | this.copy('bower.json', 'bower.json'); 92 | }; 93 | 94 | AppGenerator.prototype.jshint = function () { 95 | this.copy('jshintrc', '.jshintrc'); 96 | }; 97 | 98 | AppGenerator.prototype.editorConfig = function () { 99 | this.copy('editorconfig', '.editorconfig'); 100 | }; 101 | 102 | AppGenerator.prototype.h5bp = function () { 103 | this.copy('favicon.ico', 'app/favicon.ico'); 104 | this.copy('404.html', 'app/404.html'); 105 | this.copy('robots.txt', 'app/robots.txt'); 106 | this.copy('htaccess', 'app/.htaccess'); 107 | }; 108 | 109 | AppGenerator.prototype.mainStylesheet = function () { 110 | var css = 'main.scss'; 111 | this.copy(css, 'app/styles/' + css); 112 | }; 113 | 114 | AppGenerator.prototype.writeIndex = function () { 115 | this.indexFile = this.readFileAsString(path.join(this.sourceRoot(), 'index.html')); 116 | this.indexFile = this.engine(this.indexFile, this); 117 | 118 | // wire Bootstrap plugins 119 | if (this.includeBootstrap) { 120 | var bs = 'bower_components/bootstrap-sass-official/vendor/assets/javascripts/bootstrap/'; 121 | this.indexFile = this.appendScripts(this.indexFile, 'scripts/plugins.js', [ 122 | bs + 'affix.js', 123 | bs + 'alert.js', 124 | bs + 'dropdown.js', 125 | bs + 'tooltip.js', 126 | bs + 'modal.js', 127 | bs + 'transition.js', 128 | bs + 'button.js', 129 | bs + 'popover.js', 130 | bs + 'carousel.js', 131 | bs + 'scrollspy.js', 132 | bs + 'collapse.js', 133 | bs + 'tab.js' 134 | ]); 135 | } 136 | 137 | this.indexFile = this.appendFiles({ 138 | html: this.indexFile, 139 | fileType: 'js', 140 | optimizedPath: 'scripts/main.js', 141 | sourceFileList: ['scripts/main.js'] 142 | }); 143 | }; 144 | 145 | AppGenerator.prototype.app = function () { 146 | this.mkdir('app'); 147 | this.mkdir('app/scripts'); 148 | this.mkdir('app/styles'); 149 | this.mkdir('app/images'); 150 | this.write('app/index.html', this.indexFile); 151 | this.write('app/scripts/main.js', 'console.log(\'\\\'Allo \\\'Allo!\');'); 152 | }; 153 | 154 | AppGenerator.prototype.install = function () { 155 | var howToInstall = 156 | '\nAfter running `npm install & bower install`, inject your front end dependencies into' + 157 | '\nyour HTML by running:' + 158 | '\n' + 159 | chalk.yellow.bold('\n gulp wiredep'); 160 | 161 | if (this.options['skip-install']) { 162 | console.log(howToInstall); 163 | return; 164 | } 165 | 166 | var done = this.async(); 167 | this.installDependencies({ 168 | skipMessage: this.options['skip-install-message'], 169 | skipInstall: this.options['skip-install'], 170 | callback: function () { 171 | var bowerJson = JSON.parse(fs.readFileSync('./bower.json')); 172 | 173 | // wire Bower packages to .html 174 | wiredep({ 175 | bowerJson: bowerJson, 176 | directory: 'app/bower_components', 177 | exclude: ['bootstrap-sass'], 178 | src: 'app/index.html' 179 | }); 180 | 181 | // wire Bower packages to .scss 182 | wiredep({ 183 | bowerJson: bowerJson, 184 | directory: 'app/bower_components', 185 | src: 'app/styles/*.scss' 186 | }); 187 | 188 | done(); 189 | }.bind(this) 190 | }); 191 | }; 192 | -------------------------------------------------------------------------------- /app/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

Sorry, but the page you were trying to view does not exist.

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "browser-sync": "^0.9.1", 7 | "gulp": "^3.6.2", 8 | "gulp-bower-files": "^0.2.3", 9 | "gulp-cache": "^0.1.11", 10 | "gulp-clean": "^0.2.4", 11 | "gulp-csso": "^0.2.8", 12 | "gulp-filter": "^0.4.1", 13 | "gulp-flatten": "^0.0.2", 14 | "gulp-jshint": "^1.6.1", 15 | "gulp-load-plugins": "^0.5.1", 16 | "gulp-notify": "^1.2.6", 17 | "gulp-plumber": "^0.6.1", 18 | "gulp-sass": "^0.7.1", 19 | "gulp-uglify": "^0.3.0", 20 | "gulp-size": "^0.3.1", 21 | "gulp-useref": "^0.4.3", 22 | "gulp-util": "^2.2.14", 23 | "jshint-stylish": "^0.2.0", 24 | "opn": "^0.1.2", 25 | "wiredep": "^1.7.0", 26 | "gulp-autoprefixer": "^0.0.7", 27 | "gulp-imagemin": "^0.5.0", 28 | "streamqueue": "^0.1.0" 29 | }, 30 | "engines": { 31 | "node": ">=0.10.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/templates/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "private": true, 4 | "dependencies": {<% if (includeBootstrap) { %> 5 | "bootstrap-sass-official": "~3.1.1", 6 | <% } if (includeModernizr) { %> 7 | "modernizr": "~2.6.2",<% } %> 8 | "jquery": "~1.11.0" 9 | }, 10 | "devDependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /app/templates/bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | 23 | [package.json] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [bower.json] 28 | indent_style = space 29 | indent_size = 2 30 | -------------------------------------------------------------------------------- /app/templates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/niallobrien/generator-gulp-bootstrap/36dee8902e35a5d2416e1c808bbed5eb341d64b7/app/templates/favicon.ico -------------------------------------------------------------------------------- /app/templates/gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | app/bower_components 6 | test/bower_components 7 | -------------------------------------------------------------------------------- /app/templates/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | // generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 3 | 4 | var gulp = require('gulp'); 5 | var browserSync = require('browser-sync'); 6 | var reload = browserSync.reload; 7 | var gutil = require('gulp-util'); 8 | 9 | // load plugins 10 | var $ = require('gulp-load-plugins')(); 11 | 12 | gulp.task('styles', function () { 13 | return gulp.src('app/styles/main.scss') 14 | .pipe($.sass({errLogToConsole: true})) 15 | .pipe($.autoprefixer('last 1 version')) 16 | .pipe(gulp.dest('app/styles')) 17 | .pipe(reload({stream:true})) 18 | .pipe($.size()) 19 | .pipe($.notify("Compilation complete.")); 20 | }); 21 | 22 | gulp.task('scripts', function () { 23 | return gulp.src('app/scripts/**/*.js') 24 | .pipe($.jshint()) 25 | .pipe($.jshint.reporter(require('jshint-stylish'))) 26 | .pipe($.size()); 27 | }); 28 | 29 | gulp.task('html', ['styles', 'scripts'], function () { 30 | var jsFilter = $.filter('**/*.js'); 31 | var cssFilter = $.filter('**/*.css'); 32 | 33 | return gulp.src('app/*.html') 34 | .pipe($.useref.assets()) 35 | .pipe(jsFilter) 36 | .pipe($.uglify()) 37 | .pipe(jsFilter.restore()) 38 | .pipe(cssFilter) 39 | .pipe($.csso()) 40 | .pipe(cssFilter.restore()) 41 | .pipe($.useref.restore()) 42 | .pipe($.useref()) 43 | .pipe(gulp.dest('dist')) 44 | .pipe($.size()); 45 | }); 46 | 47 | gulp.task('images', function () { 48 | return gulp.src('app/images/**/*') 49 | .pipe($.cache($.imagemin({ 50 | optimizationLevel: 3, 51 | progressive: true, 52 | interlaced: true 53 | }))) 54 | .pipe(gulp.dest('dist/images')) 55 | .pipe(reload({stream:true, once:true})) 56 | .pipe($.size()); 57 | }); 58 | 59 | gulp.task('fonts', function () { 60 | var streamqueue = require('streamqueue'); 61 | return streamqueue({objectMode: true}, 62 | $.bowerFiles(), 63 | gulp.src('app/fonts/**/*') 64 | ) 65 | .pipe($.filter('**/*.{eot,svg,ttf,woff}')) 66 | .pipe($.flatten()) 67 | .pipe(gulp.dest('dist/fonts')) 68 | .pipe($.size()); 69 | }); 70 | 71 | gulp.task('clean', function () { 72 | return gulp.src(['app/styles/main.css', 'dist'], { read: false }).pipe($.clean()); 73 | }); 74 | 75 | gulp.task('build', ['html', 'images', 'fonts']); 76 | 77 | gulp.task('default', ['clean'], function () { 78 | gulp.start('build'); 79 | }); 80 | 81 | gulp.task('serve', ['styles'], function () { 82 | browserSync.init(null, { 83 | server: { 84 | baseDir: 'app', 85 | directory: true 86 | }, 87 | debugInfo: false, 88 | open: false, 89 | hostnameSuffix: ".xip.io" 90 | }, function (err, bs) { 91 | require('opn')(bs.options.url); 92 | console.log('Started connect web server on ' + bs.options.url); 93 | }); 94 | }); 95 | 96 | // inject bower components 97 | gulp.task('wiredep', function () { 98 | var wiredep = require('wiredep').stream; 99 | gulp.src('app/styles/*.scss') 100 | .pipe(wiredep({ 101 | directory: 'app/bower_components' 102 | })) 103 | .pipe(gulp.dest('app/styles')); 104 | gulp.src('app/*.html') 105 | .pipe(wiredep({ 106 | directory: 'app/bower_components', 107 | exclude: ['bootstrap-sass-official'] 108 | })) 109 | .pipe(gulp.dest('app')); 110 | }); 111 | 112 | gulp.task('watch', ['serve'], function () { 113 | 114 | // watch for changes 115 | gulp.watch(['app/*.html'], reload); 116 | 117 | gulp.watch('app/styles/**/*.scss', ['styles']); 118 | gulp.watch('app/scripts/**/*.js', ['scripts']); 119 | gulp.watch('app/images/**/*', ['images']); 120 | gulp.watch('bower.json', ['wiredep']); 121 | }); 122 | -------------------------------------------------------------------------------- /app/templates/htaccess: -------------------------------------------------------------------------------- 1 | # Apache Server Configs v2.2.0 | MIT License 2 | # https://github.com/h5bp/server-configs-apache 3 | 4 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 5 | # to the main server config file (usually called `httpd.conf`), you should add 6 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 7 | 8 | # ############################################################################## 9 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 10 | # ############################################################################## 11 | 12 | # ------------------------------------------------------------------------------ 13 | # | Cross-domain AJAX requests | 14 | # ------------------------------------------------------------------------------ 15 | 16 | # Allow cross-origin AJAX requests. 17 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 18 | # http://enable-cors.org/ 19 | 20 | # 21 | # Header set Access-Control-Allow-Origin "*" 22 | # 23 | 24 | # ------------------------------------------------------------------------------ 25 | # | CORS-enabled images | 26 | # ------------------------------------------------------------------------------ 27 | 28 | # Send the CORS header for images when browsers request it. 29 | # https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image 30 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 31 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 32 | 33 | 34 | 35 | 36 | SetEnvIf Origin ":" IS_CORS 37 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 38 | 39 | 40 | 41 | 42 | # ------------------------------------------------------------------------------ 43 | # | Web fonts access | 44 | # ------------------------------------------------------------------------------ 45 | 46 | # Allow access to web fonts from all domains. 47 | 48 | 49 | 50 | Header set Access-Control-Allow-Origin "*" 51 | 52 | 53 | 54 | 55 | # ############################################################################## 56 | # # ERRORS # 57 | # ############################################################################## 58 | 59 | # ------------------------------------------------------------------------------ 60 | # | 404 error prevention for non-existing redirected folders | 61 | # ------------------------------------------------------------------------------ 62 | 63 | # Prevent Apache from returning a 404 error as the result of a rewrite 64 | # when the directory with the same name does not exist. 65 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 66 | # http://www.webmasterworld.com/apache/3808792.htm 67 | 68 | Options -MultiViews 69 | 70 | # ------------------------------------------------------------------------------ 71 | # | Custom error messages / pages | 72 | # ------------------------------------------------------------------------------ 73 | 74 | # Customize what Apache returns to the client in case of an error. 75 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument 76 | 77 | ErrorDocument 404 /404.html 78 | 79 | 80 | # ############################################################################## 81 | # # INTERNET EXPLORER # 82 | # ############################################################################## 83 | 84 | # ------------------------------------------------------------------------------ 85 | # | Better website experience | 86 | # ------------------------------------------------------------------------------ 87 | 88 | # Force Internet Explorer to render pages in the highest available mode 89 | # in the various cases when it may not. 90 | # http://hsivonen.iki.fi/doctype/ie-mode.pdf 91 | 92 | 93 | Header set X-UA-Compatible "IE=edge" 94 | # `mod_headers` cannot match based on the content-type, however, this 95 | # header should be send only for HTML pages and not for the other resources 96 | 97 | Header unset X-UA-Compatible 98 | 99 | 100 | 101 | # ------------------------------------------------------------------------------ 102 | # | Cookie setting from iframes | 103 | # ------------------------------------------------------------------------------ 104 | 105 | # Allow cookies to be set from iframes in Internet Explorer. 106 | # http://msdn.microsoft.com/en-us/library/ms537343.aspx 107 | # http://www.w3.org/TR/2000/CR-P3P-20001215/ 108 | 109 | # 110 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 111 | # 112 | 113 | 114 | # ############################################################################## 115 | # # MIME TYPES AND ENCODING # 116 | # ############################################################################## 117 | 118 | # ------------------------------------------------------------------------------ 119 | # | Proper MIME types for all files | 120 | # ------------------------------------------------------------------------------ 121 | 122 | 123 | 124 | # Audio 125 | AddType audio/mp4 m4a f4a f4b 126 | AddType audio/ogg oga ogg opus 127 | 128 | # Data interchange 129 | AddType application/json json map 130 | AddType application/ld+json jsonld 131 | 132 | # JavaScript 133 | # Normalize to standard type. 134 | # http://tools.ietf.org/html/rfc4329#section-7.2 135 | AddType application/javascript js 136 | 137 | # Video 138 | AddType video/mp4 f4v f4p m4v mp4 139 | AddType video/ogg ogv 140 | AddType video/webm webm 141 | AddType video/x-flv flv 142 | 143 | # Web fonts 144 | AddType application/font-woff woff 145 | AddType application/vnd.ms-fontobject eot 146 | 147 | # Browsers usually ignore the font MIME types and simply sniff the bytes 148 | # to figure out the font type. 149 | # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern 150 | 151 | # Chrome however, shows a warning if any other MIME types are used for 152 | # the following fonts. 153 | 154 | AddType application/x-font-ttf ttc ttf 155 | AddType font/opentype otf 156 | 157 | # Make SVGZ fonts work on the iPad. 158 | # https://twitter.com/FontSquirrel/status/14855840545 159 | AddType image/svg+xml svgz 160 | AddEncoding gzip svgz 161 | 162 | # Other 163 | AddType application/octet-stream safariextz 164 | AddType application/x-chrome-extension crx 165 | AddType application/x-opera-extension oex 166 | AddType application/x-web-app-manifest+json webapp 167 | AddType application/x-xpinstall xpi 168 | AddType application/xml atom rdf rss xml 169 | AddType image/webp webp 170 | AddType image/x-icon cur 171 | AddType text/cache-manifest appcache manifest 172 | AddType text/vtt vtt 173 | AddType text/x-component htc 174 | AddType text/x-vcard vcf 175 | 176 | 177 | 178 | # ------------------------------------------------------------------------------ 179 | # | UTF-8 encoding | 180 | # ------------------------------------------------------------------------------ 181 | 182 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 183 | AddDefaultCharset utf-8 184 | 185 | # Force UTF-8 for certain file formats. 186 | 187 | AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml 188 | 189 | 190 | 191 | # ############################################################################## 192 | # # URL REWRITES # 193 | # ############################################################################## 194 | 195 | # ------------------------------------------------------------------------------ 196 | # | Rewrite engine | 197 | # ------------------------------------------------------------------------------ 198 | 199 | # Turn on the rewrite engine and enable the `FollowSymLinks` option (this is 200 | # necessary in order for the following directives to work). 201 | 202 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 203 | # comment it out and use `Options +SymLinksIfOwnerMatch`, but be aware of the 204 | # performance impact. 205 | # http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 206 | 207 | # Also, some cloud hosting services require `RewriteBase` to be set. 208 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 209 | 210 | 211 | Options +FollowSymlinks 212 | # Options +SymLinksIfOwnerMatch 213 | RewriteEngine On 214 | # RewriteBase / 215 | 216 | 217 | # ------------------------------------------------------------------------------ 218 | # | Suppressing / Forcing the `www.` at the beginning of URLs | 219 | # ------------------------------------------------------------------------------ 220 | 221 | # The same content should never be available under two different URLs, 222 | # especially not with and without `www.` at the beginning. This can cause 223 | # SEO problems (duplicate content), and therefore, you should choose one 224 | # of the alternatives and redirect the other one. 225 | 226 | # By default `Option 1` (no `www.`) is activated. 227 | # http://no-www.org/faq.php?q=class_b 228 | 229 | # If you would prefer to use `Option 2`, just comment out all the lines 230 | # from `Option 1` and uncomment the ones from `Option 2`. 231 | 232 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 233 | 234 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 235 | 236 | # Option 1: rewrite www.example.com → example.com 237 | 238 | 239 | RewriteCond %{HTTPS} !=on 240 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 241 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 242 | 243 | 244 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 245 | 246 | # Option 2: rewrite example.com → www.example.com 247 | 248 | # Be aware that the following might not be a good idea if you use "real" 249 | # subdomains for certain parts of your website. 250 | 251 | # 252 | # RewriteCond %{HTTPS} !=on 253 | # RewriteCond %{HTTP_HOST} !^www\. [NC] 254 | # RewriteCond %{SERVER_ADDR} !=127.0.0.1 255 | # RewriteCond %{SERVER_ADDR} !=::1 256 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 257 | # 258 | 259 | 260 | # ############################################################################## 261 | # # SECURITY # 262 | # ############################################################################## 263 | 264 | # ------------------------------------------------------------------------------ 265 | # | Clickjacking | 266 | # ------------------------------------------------------------------------------ 267 | 268 | # Protect website against clickjacking. 269 | 270 | # The example below sends the `X-Frame-Options` response header with the value 271 | # `DENY`, informing browsers not to display the web page content in any frame. 272 | 273 | # This might not be the best setting for everyone. You should read about the 274 | # other two possible values for `X-Frame-Options`: `SAMEORIGIN` & `ALLOW-FROM`. 275 | # http://tools.ietf.org/html/rfc7034#section-2.1 276 | 277 | # Keep in mind that while you could send the `X-Frame-Options` header for all 278 | # of your site’s pages, this has the potential downside that it forbids even 279 | # non-malicious framing of your content (e.g.: when users visit your site using 280 | # a Google Image Search results page). 281 | 282 | # Nonetheless, you should ensure that you send the `X-Frame-Options` header for 283 | # all pages that allow a user to make a state changing operation (e.g: pages 284 | # that contain one-click purchase links, checkout or bank-transfer confirmation 285 | # pages, pages that make permanent configuration changes, etc.). 286 | 287 | # Sending the `X-Frame-Options` header can also protect your website against 288 | # more than just clickjacking attacks: https://cure53.de/xfo-clickjacking.pdf. 289 | 290 | # http://tools.ietf.org/html/rfc7034 291 | # http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx 292 | # https://www.owasp.org/index.php/Clickjacking 293 | 294 | # 295 | # Header set X-Frame-Options "DENY" 296 | # 297 | # Header unset X-Frame-Options 298 | # 299 | # 300 | 301 | # ------------------------------------------------------------------------------ 302 | # | Content Security Policy (CSP) | 303 | # ------------------------------------------------------------------------------ 304 | 305 | # Mitigate the risk of cross-site scripting and other content-injection attacks. 306 | 307 | # This can be done by setting a `Content Security Policy` which whitelists 308 | # trusted sources of content for your website. 309 | 310 | # The example header below allows ONLY scripts that are loaded from the current 311 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 312 | # work as-is for your site! 313 | 314 | # For more details on how to craft a reasonable policy for your site, read: 315 | # http://html5rocks.com/en/tutorials/security/content-security-policy (or the 316 | # specification: http://w3.org/TR/CSP). Also, to make things easier, you can 317 | # use an online CSP header generator such as: http://cspisawesome.com/. 318 | 319 | # 320 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 321 | # 322 | # Header unset Content-Security-Policy 323 | # 324 | # 325 | 326 | # ------------------------------------------------------------------------------ 327 | # | File access | 328 | # ------------------------------------------------------------------------------ 329 | 330 | # Block access to directories without a default document. 331 | # You should leave the following uncommented, as you shouldn't allow anyone to 332 | # surf through every directory on your server (which may includes rather private 333 | # places such as the CMS's directories). 334 | 335 | 336 | Options -Indexes 337 | 338 | 339 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 340 | 341 | # Block access to hidden files and directories. 342 | # This includes directories used by version control systems such as Git and SVN. 343 | 344 | 345 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 346 | RewriteCond %{SCRIPT_FILENAME} -f 347 | RewriteRule "(^|/)\." - [F] 348 | 349 | 350 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 351 | 352 | # Block access to files that can expose sensitive information. 353 | 354 | # By default, block access to backup and source files that may be left by some 355 | # text editors and can pose a security risk when anyone has access to them. 356 | # http://feross.org/cmsploit/ 357 | 358 | # IMPORTANT: Update the `` regular expression from below to include 359 | # any files that might end up on your production server and can expose sensitive 360 | # information about your website. These files may include: configuration files, 361 | # files that contain metadata about the project (e.g.: project dependencies), 362 | # build scripts, etc.. 363 | 364 | 365 | 366 | # Apache < 2.3 367 | 368 | Order allow,deny 369 | Deny from all 370 | Satisfy All 371 | 372 | 373 | # Apache ≥ 2.3 374 | 375 | Require all denied 376 | 377 | 378 | 379 | 380 | # ------------------------------------------------------------------------------ 381 | # | Reducing MIME-type security risks | 382 | # ------------------------------------------------------------------------------ 383 | 384 | # Prevent some browsers from MIME-sniffing the response. 385 | 386 | # This reduces exposure to drive-by download attacks and should be enable 387 | # especially if the web server is serving user uploaded content, content 388 | # that could potentially be treated by the browser as executable. 389 | 390 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx 391 | # http://msdn.microsoft.com/en-us/library/ie/gg622941.aspx 392 | # http://mimesniff.spec.whatwg.org/ 393 | 394 | # 395 | # Header set X-Content-Type-Options "nosniff" 396 | # 397 | 398 | # ------------------------------------------------------------------------------ 399 | # | Reflected Cross-Site Scripting (XSS) attacks | 400 | # ------------------------------------------------------------------------------ 401 | 402 | # (1) Try to re-enable the Cross-Site Scripting (XSS) filter built into the 403 | # most recent web browsers. 404 | # 405 | # The filter is usually enabled by default, but in some cases it may be 406 | # disabled by the user. However, in Internet Explorer for example, it can 407 | # be re-enabled just by sending the `X-XSS-Protection` header with the 408 | # value of `1`. 409 | # 410 | # (2) Prevent web browsers from rendering the web page if a potential reflected 411 | # (a.k.a non-persistent) XSS attack is detected by the filter. 412 | # 413 | # By default, if the filter is enabled and browsers detect a reflected 414 | # XSS attack, they will attempt to block the attack by making the smallest 415 | # possible modifications to the returned web page. 416 | # 417 | # Unfortunately, in some browsers (e.g.: Internet Explorer), this default 418 | # behavior may allow the XSS filter to be exploited, thereby, it's better 419 | # to tell browsers to prevent the rendering of the page altogether, instead 420 | # of attempting to modify it. 421 | # 422 | # http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities 423 | # 424 | # IMPORTANT: Do not rely on the XSS filter to prevent XSS attacks! Ensure that 425 | # you are taking all possible measures to prevent XSS attacks, the most obvious 426 | # being: validating and sanitizing your site's inputs. 427 | # 428 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx 429 | # http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx 430 | # https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 431 | 432 | # 433 | # # (1) (2) 434 | # Header set X-XSS-Protection "1; mode=block" 435 | # 436 | # Header unset X-XSS-Protection 437 | # 438 | # 439 | 440 | # ------------------------------------------------------------------------------ 441 | # | Secure Sockets Layer (SSL) | 442 | # ------------------------------------------------------------------------------ 443 | 444 | # Rewrite secure requests properly in order to prevent SSL certificate warnings. 445 | # E.g.: prevent `https://www.example.com` when your certificate only allows 446 | # `https://secure.example.com`. 447 | 448 | # 449 | # RewriteCond %{SERVER_PORT} !^443 450 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 451 | # 452 | 453 | # ------------------------------------------------------------------------------ 454 | # | HTTP Strict Transport Security (HSTS) | 455 | # ------------------------------------------------------------------------------ 456 | 457 | # Force client-side SSL redirection. 458 | 459 | # If a user types `example.com` in his browser, the above rule will redirect 460 | # him to the secure version of the site. That still leaves a window of 461 | # opportunity (the initial HTTP connection) for an attacker to downgrade or 462 | # redirect the request. 463 | 464 | # The following header ensures that browser will ONLY connect to your server 465 | # via HTTPS, regardless of what the users type in the address bar. 466 | 467 | # http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 468 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 469 | 470 | # IMPORTANT: Remove the `includeSubDomains` optional directive if the subdomains 471 | # are not using HTTPS. 472 | 473 | # 474 | # Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" 475 | # 476 | 477 | # ------------------------------------------------------------------------------ 478 | # | Server software information | 479 | # ------------------------------------------------------------------------------ 480 | 481 | # Avoid displaying the exact Apache version number, the description of the 482 | # generic OS-type and the information about Apache's compiled-in modules. 483 | 484 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 485 | 486 | # ServerTokens Prod 487 | 488 | 489 | # ############################################################################## 490 | # # WEB PERFORMANCE # 491 | # ############################################################################## 492 | 493 | # ------------------------------------------------------------------------------ 494 | # | Compression | 495 | # ------------------------------------------------------------------------------ 496 | 497 | 498 | 499 | # Force compression for mangled headers. 500 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 501 | 502 | 503 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 504 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 505 | 506 | 507 | 508 | # Compress all output labeled with one of the following MIME-types 509 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 510 | # and can remove the `` and `` lines 511 | # as `AddOutputFilterByType` is still in the core directives). 512 | 513 | AddOutputFilterByType DEFLATE application/atom+xml \ 514 | application/javascript \ 515 | application/json \ 516 | application/ld+json \ 517 | application/rss+xml \ 518 | application/vnd.ms-fontobject \ 519 | application/x-font-ttf \ 520 | application/x-web-app-manifest+json \ 521 | application/xhtml+xml \ 522 | application/xml \ 523 | font/opentype \ 524 | image/svg+xml \ 525 | image/x-icon \ 526 | text/css \ 527 | text/html \ 528 | text/plain \ 529 | text/x-component \ 530 | text/xml 531 | 532 | 533 | 534 | 535 | # ------------------------------------------------------------------------------ 536 | # | Content transformations | 537 | # ------------------------------------------------------------------------------ 538 | 539 | # Prevent mobile network providers from modifying the website's content. 540 | # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 541 | 542 | # 543 | # Header set Cache-Control "no-transform" 544 | # 545 | 546 | # ------------------------------------------------------------------------------ 547 | # | ETags | 548 | # ------------------------------------------------------------------------------ 549 | 550 | # Remove `ETags` as resources are sent with far-future expires headers. 551 | # http://developer.yahoo.com/performance/rules.html#etags. 552 | 553 | # `FileETag None` doesn't work in all cases. 554 | 555 | Header unset ETag 556 | 557 | 558 | FileETag None 559 | 560 | # ------------------------------------------------------------------------------ 561 | # | Expires headers | 562 | # ------------------------------------------------------------------------------ 563 | 564 | # The following expires headers are set pretty far in the future. If you 565 | # don't control versioning with filename-based cache busting, consider 566 | # lowering the cache time for resources such as style sheets and JavaScript 567 | # files to something like one week. 568 | 569 | 570 | 571 | ExpiresActive on 572 | ExpiresDefault "access plus 1 month" 573 | 574 | # CSS 575 | ExpiresByType text/css "access plus 1 year" 576 | 577 | # Data interchange 578 | ExpiresByType application/json "access plus 0 seconds" 579 | ExpiresByType application/ld+json "access plus 0 seconds" 580 | ExpiresByType application/xml "access plus 0 seconds" 581 | ExpiresByType text/xml "access plus 0 seconds" 582 | 583 | # Favicon (cannot be renamed!) and cursor images 584 | ExpiresByType image/x-icon "access plus 1 week" 585 | 586 | # HTML components (HTCs) 587 | ExpiresByType text/x-component "access plus 1 month" 588 | 589 | # HTML 590 | ExpiresByType text/html "access plus 0 seconds" 591 | 592 | # JavaScript 593 | ExpiresByType application/javascript "access plus 1 year" 594 | 595 | # Manifest files 596 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 597 | ExpiresByType text/cache-manifest "access plus 0 seconds" 598 | 599 | # Media 600 | ExpiresByType audio/ogg "access plus 1 month" 601 | ExpiresByType image/gif "access plus 1 month" 602 | ExpiresByType image/jpeg "access plus 1 month" 603 | ExpiresByType image/png "access plus 1 month" 604 | ExpiresByType video/mp4 "access plus 1 month" 605 | ExpiresByType video/ogg "access plus 1 month" 606 | ExpiresByType video/webm "access plus 1 month" 607 | 608 | # Web feeds 609 | ExpiresByType application/atom+xml "access plus 1 hour" 610 | ExpiresByType application/rss+xml "access plus 1 hour" 611 | 612 | # Web fonts 613 | ExpiresByType application/font-woff "access plus 1 month" 614 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 615 | ExpiresByType application/x-font-ttf "access plus 1 month" 616 | ExpiresByType font/opentype "access plus 1 month" 617 | ExpiresByType image/svg+xml "access plus 1 month" 618 | 619 | 620 | 621 | # ------------------------------------------------------------------------------ 622 | # | Filename-based cache busting | 623 | # ------------------------------------------------------------------------------ 624 | 625 | # If you're not using a build process to manage your filename version revving, 626 | # you might want to consider enabling the following directives to route all 627 | # requests such as `/css/style.12345.css` to `/css/style.css`. 628 | 629 | # To understand why this is important and a better idea than `*.css?v231`, read: 630 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 631 | 632 | # 633 | # RewriteCond %{REQUEST_FILENAME} !-f 634 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] 635 | # 636 | 637 | # ------------------------------------------------------------------------------ 638 | # | File concatenation | 639 | # ------------------------------------------------------------------------------ 640 | 641 | # Allow concatenation from within specific style sheets and JavaScript files. 642 | 643 | # e.g.: 644 | # 645 | # If you have the following content in a file 646 | # 647 | # 648 | # 649 | # 650 | # Apache will replace it with the content from the specified files. 651 | 652 | # 653 | # 654 | # Options +Includes 655 | # AddOutputFilterByType INCLUDES application/javascript application/json 656 | # SetOutputFilter INCLUDES 657 | # 658 | # 659 | # Options +Includes 660 | # AddOutputFilterByType INCLUDES text/css 661 | # SetOutputFilter INCLUDES 662 | # 663 | # 664 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= appname %> 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | <% if (includeModernizr) { %> 19 | 20 | 21 | <% } %> 22 | 23 | 24 | 27 | <% if (includeBootstrap) { %> 28 |
29 |
30 | 35 |

<%= appname %>

36 |
37 | 38 |
39 |

'Allo, 'Allo!

40 |

Always a pleasure scaffolding your apps.

41 |

Splendid!

42 |
43 | 44 |
45 |
46 |

HTML5 Boilerplate

47 |

HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.

48 |

Sass (libsass)

49 |

Sass is the most mature, stable, and powerful professional grade CSS extension language in the world.
50 | At the core we're using Libsass which is an implemention of Sass written in C. Gulp-sass utilises node-sass which in turn utilises Libsass.

51 |

Bootstrap

52 |

Sleek, intuitive, and powerful mobile first front-end framework for faster and easier web development.

<% if (includeModernizr) { %> 53 |

Modernizr

54 |

Modernizr is an open-source JavaScript library that helps you build the next generation of HTML5 and CSS3-powered websites.

55 | <% } %> 56 |
57 |
58 | 59 | 62 |
63 | <% } else { %> 64 |
65 |

'Allo, 'Allo!

66 |

You now have

67 |
    68 |
  • HTML5 Boilerplate
  • <% if (includeModernizr) { %> 69 |
  • Modernizr
  • <% } %> 70 |
71 |
72 | <% } %> 73 | 74 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /app/templates/jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "jquery": true 21 | } 22 | -------------------------------------------------------------------------------- /app/templates/main.css: -------------------------------------------------------------------------------- 1 | <% if (includeBootstrap) { %>.browsehappy { 2 | margin: 0.2em 0; 3 | background: #ccc; 4 | color: #000; 5 | padding: 0.2em 0; 6 | } 7 | 8 | /* Space out content a bit */ 9 | body { 10 | padding-top: 20px; 11 | padding-bottom: 20px; 12 | } 13 | 14 | /* Everything but the jumbotron gets side spacing for mobile first views */ 15 | .header, 16 | .marketing, 17 | .footer { 18 | padding-left: 15px; 19 | padding-right: 15px; 20 | } 21 | 22 | /* Custom page header */ 23 | .header { 24 | border-bottom: 1px solid #e5e5e5; 25 | } 26 | 27 | /* Make the masthead heading the same height as the navigation */ 28 | .header h3 { 29 | margin-top: 0; 30 | margin-bottom: 0; 31 | line-height: 40px; 32 | padding-bottom: 19px; 33 | } 34 | 35 | /* Custom page footer */ 36 | .footer { 37 | padding-top: 19px; 38 | color: #777; 39 | border-top: 1px solid #e5e5e5; 40 | } 41 | 42 | .container-narrow > hr { 43 | margin: 30px 0; 44 | } 45 | 46 | /* Main marketing message and sign up button */ 47 | .jumbotron { 48 | text-align: center; 49 | border-bottom: 1px solid #e5e5e5; 50 | } 51 | 52 | .jumbotron .btn { 53 | font-size: 21px; 54 | padding: 14px 24px; 55 | } 56 | 57 | /* Supporting marketing content */ 58 | .marketing { 59 | margin: 40px 0; 60 | } 61 | 62 | .marketing p + h4 { 63 | margin-top: 28px; 64 | } 65 | 66 | /* Responsive: Portrait tablets and up */ 67 | @media screen and (min-width: 768px) { 68 | .container { 69 | max-width: 730px; 70 | } 71 | 72 | /* Remove the padding we set earlier */ 73 | .header, 74 | .marketing, 75 | .footer { 76 | padding-left: 0; 77 | padding-right: 0; 78 | } 79 | 80 | /* Space out the masthead */ 81 | .header { 82 | margin-bottom: 30px; 83 | } 84 | 85 | /* Remove the bottom border on the jumbotron for visual effect */ 86 | .jumbotron { 87 | border-bottom: 0; 88 | } 89 | }<% } else { %>body { 90 | background: #fafafa; 91 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 92 | color: #333; 93 | } 94 | 95 | .hero-unit { 96 | margin: 50px auto 0 auto; 97 | width: 300px; 98 | font-size: 18px; 99 | font-weight: 200; 100 | line-height: 30px; 101 | background-color: #eee; 102 | border-radius: 6px; 103 | padding: 60px; 104 | } 105 | 106 | .hero-unit h1 { 107 | font-size: 60px; 108 | line-height: 1; 109 | letter-spacing: -1px; 110 | } 111 | 112 | .browsehappy { 113 | margin: 0.2em 0; 114 | background: #ccc; 115 | color: #000; 116 | padding: 0.2em 0; 117 | }<% } %> -------------------------------------------------------------------------------- /app/templates/main.scss: -------------------------------------------------------------------------------- 1 | <% if (includeBootstrap) { %>$icon-font-path: "../bower_components/bootstrap-sass-official/vendor/assets/fonts/bootstrap/"; 2 | 3 | // bower:scss 4 | // endbower 5 | 6 | .browsehappy { 7 | margin: 0.2em 0; 8 | background: #ccc; 9 | color: #000; 10 | padding: 0.2em 0; 11 | } 12 | 13 | /* Space out content a bit */ 14 | body { 15 | padding-top: 20px; 16 | padding-bottom: 20px; 17 | } 18 | 19 | /* Everything but the jumbotron gets side spacing for mobile first views */ 20 | .header, 21 | .marketing, 22 | .footer { 23 | padding-left: 15px; 24 | padding-right: 15px; 25 | } 26 | 27 | /* Custom page header */ 28 | .header { 29 | border-bottom: 1px solid #e5e5e5; 30 | 31 | /* Make the masthead heading the same height as the navigation */ 32 | h3 { 33 | margin-top: 0; 34 | margin-bottom: 0; 35 | line-height: 40px; 36 | padding-bottom: 19px; 37 | } 38 | } 39 | 40 | /* Custom page footer */ 41 | .footer { 42 | padding-top: 19px; 43 | color: #777; 44 | border-top: 1px solid #e5e5e5; 45 | } 46 | 47 | .container-narrow > hr { 48 | margin: 30px 0; 49 | } 50 | 51 | /* Main marketing message and sign up button */ 52 | .jumbotron { 53 | text-align: center; 54 | border-bottom: 1px solid #e5e5e5; 55 | .btn { 56 | font-size: 21px; 57 | padding: 14px 24px; 58 | } 59 | } 60 | 61 | /* Supporting marketing content */ 62 | .marketing { 63 | margin: 40px 0; 64 | p + h4 { 65 | margin-top: 28px; 66 | } 67 | } 68 | 69 | /* Responsive: Portrait tablets and up */ 70 | @media screen and (min-width: 768px) { 71 | .container { 72 | max-width: 730px; 73 | } 74 | 75 | /* Remove the padding we set earlier */ 76 | .header, 77 | .marketing, 78 | .footer { 79 | padding-left: 0; 80 | padding-right: 0; 81 | } 82 | 83 | /* Space out the masthead */ 84 | .header { 85 | margin-bottom: 30px; 86 | } 87 | 88 | /* Remove the bottom border on the jumbotron for visual effect */ 89 | .jumbotron { 90 | border-bottom: 0; 91 | } 92 | }<% } else { %>body { 93 | background: #fafafa; 94 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 95 | color: #333; 96 | } 97 | 98 | .hero-unit { 99 | margin: 50px auto 0 auto; 100 | width: 300px; 101 | font-size: 18px; 102 | font-weight: 200; 103 | line-height: 30px; 104 | background-color: #eee; 105 | border-radius: 6px; 106 | padding: 60px; 107 | h1 { 108 | font-size: 60px; 109 | line-height: 1; 110 | letter-spacing: -1px; 111 | } 112 | } 113 | 114 | .browsehappy { 115 | margin: 0.2em 0; 116 | background: #ccc; 117 | color: #000; 118 | padding: 0.2em 0; 119 | }<% } %> 120 | -------------------------------------------------------------------------------- /app/templates/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-gulp-bootstrap", 3 | "version": "0.0.4", 4 | "description": "Scaffold out a front-end web app using Sass (node-sass) by default", 5 | "license": "BSD", 6 | "repository": "niallobrien/generator-gulp-bootstrap", 7 | "author": "Niall O'Brien", 8 | "main": "app/index.js", 9 | "engines": { 10 | "node": ">=0.10.0", 11 | "npm": ">=1.3" 12 | }, 13 | "scripts": { 14 | "test": "mocha --reporter spec" 15 | }, 16 | "files": [ 17 | "app" 18 | ], 19 | "keywords": [ 20 | "yeoman-generator", 21 | "web", 22 | "app", 23 | "front-end", 24 | "h5bp", 25 | "modernizr", 26 | "jquery", 27 | "gulp" 28 | ], 29 | "dependencies": { 30 | "chalk": "^0.4.0", 31 | "cheerio": "^0.15.0", 32 | "wiredep": "^1.4.3", 33 | "yeoman-generator": "^0.16.0" 34 | }, 35 | "peerDependencies": { 36 | "yo": ">=1.0.0", 37 | "generator-mocha": ">=0.1.0", 38 | "gulp": ">=3.5.0" 39 | }, 40 | "devDependencies": { 41 | "mocha": "*" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/app_slug.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | 'use strict'; 4 | var fs = require('fs'); 5 | var util = require('util'); 6 | var path = require('path'); 7 | var assert = require('assert'); 8 | var helpers = require('yeoman-generator').test; 9 | 10 | describe('Gulp Webapp generator slug name', function () { 11 | beforeEach(function (done) { 12 | helpers.testDirectory(path.join(__dirname, 'slug'), function (err) { 13 | if (err) { 14 | return done(err); 15 | } 16 | 17 | this.webapp = helpers.createGenerator('gulp-webapp:app', [ 18 | '../../app', [ 19 | helpers.createDummyGenerator(), 20 | 'mocha:app' 21 | ] 22 | ]); 23 | this.webapp.options['skip-install'] = true; 24 | 25 | done(); 26 | }.bind(this)); 27 | }); 28 | 29 | it('should generate the same appName in every file', function (done) { 30 | var expectedAppName = 'slug'; 31 | var expected = [ 32 | 'package.json', 33 | 'bower.json', 34 | 'app/index.html' 35 | ]; 36 | helpers.mockPrompt(this.webapp, { 37 | // features: ['includeSass'] 38 | }); 39 | 40 | this.webapp.run({}, function () { 41 | // Check if all files are created for the test 42 | helpers.assertFile(expected); 43 | 44 | // read JS Files 45 | var packageJson = fs.readFileSync('package.json', 'utf8'); 46 | var bowerJson = fs.readFileSync('bower.json', 'utf8'); 47 | 48 | // Test JS Files 49 | var regexJs = new RegExp('"name": "' + expectedAppName + '"'); 50 | assert.ok(regexJs.test(packageJson), 'package.json template using a wrong appName'); 51 | assert.ok(regexJs.test(bowerJson), 'bower.json template using a wrong appName'); 52 | 53 | // read HTML file 54 | var indexHtml = fs.readFileSync('app/index.html', 'utf8'); 55 | 56 | // Test HTML File 57 | var regexHtml = new RegExp('' + expectedAppName + ''); 58 | assert.ok(regexHtml.test(indexHtml), 'index.html template using a wrong appName'); 59 | done(); 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /test/gulp_file.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | 'use strict'; 4 | var fs = require('fs'); 5 | var util = require('util'); 6 | var path = require('path'); 7 | var assert = require('assert'); 8 | var helpers = require('yeoman-generator').test; 9 | 10 | describe('Gulp Webapp generator: tasks', function () { 11 | beforeEach(function (done) { 12 | helpers.testDirectory(path.join(__dirname, 'gulp-file'), function (err) { 13 | if (err) { 14 | return done(err); 15 | } 16 | 17 | this.webapp = helpers.createGenerator('gulp-webapp:app', [ 18 | '../../app', [ 19 | helpers.createDummyGenerator(), 20 | 'mocha:app' 21 | ] 22 | ]); 23 | this.webapp.options['skip-install'] = true; 24 | 25 | done(); 26 | }.bind(this)); 27 | }); 28 | 29 | var assertTaskExists = function (generator, taskName, features, done) { 30 | helpers.mockPrompt(generator, { 31 | features: features 32 | }); 33 | 34 | generator.run({}, function () { 35 | var gulpFile = fs.readFileSync('gulpfile.js', 'utf8'); 36 | var regexGulp = new RegExp('gulp.task\\(\'' + taskName + '\''); 37 | 38 | assert.ok( 39 | regexGulp.test(gulpFile), 40 | 'gulpfile.js does not contain ' + taskName + ' task' 41 | ); 42 | done(); 43 | }); 44 | }; 45 | 46 | it('should contain styles task without Sass included', function (done) { 47 | assertTaskExists(this.webapp, "styles", [], done); 48 | }); 49 | 50 | it('should contain styles task with Sass included', function (done) { 51 | // assertTaskExists(this.webapp, "styles", ['includeSass'], done); 52 | }); 53 | 54 | it('should contain scripts task', function (done) { 55 | assertTaskExists(this.webapp, "scripts", [], done); 56 | }); 57 | 58 | it('should contain html task', function (done) { 59 | assertTaskExists(this.webapp, "html", [], done); 60 | }); 61 | 62 | it('should contain images task', function (done) { 63 | assertTaskExists(this.webapp, "images", [], done); 64 | }); 65 | 66 | it('should contain fonts task', function (done) { 67 | assertTaskExists(this.webapp, "fonts", [], done); 68 | }); 69 | 70 | it('should contain clean task', function (done) { 71 | assertTaskExists(this.webapp, "clean", [], done); 72 | }); 73 | 74 | it('should contain build task', function (done) { 75 | assertTaskExists(this.webapp, "build", [], done); 76 | }); 77 | 78 | it('should contain connect task', function (done) { 79 | assertTaskExists(this.webapp, "connect", [], done); 80 | }); 81 | 82 | it('should contain wiredep task', function (done) { 83 | assertTaskExists(this.webapp, "wiredep", [], done); 84 | }); 85 | 86 | it('should contain watch task', function (done) { 87 | assertTaskExists(this.webapp, "watch", [], done); 88 | }); 89 | 90 | it('should contain default task', function (done) { 91 | assertTaskExists(this.webapp, "watch", [], done); 92 | }); 93 | 94 | it('should contain default serve', function (done) { 95 | assertTaskExists(this.webapp, "serve", [], done); 96 | }); 97 | 98 | }); 99 | -------------------------------------------------------------------------------- /test/sass_feature.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | 'use strict'; 4 | var path = require('path'); 5 | var helpers = require('yeoman-generator').test; 6 | 7 | describe('Gulp webapp generator: sass feature', function () { 8 | beforeEach(function (done) { 9 | helpers.testDirectory(path.join(__dirname, 'sass'), function (err) { 10 | if (err) { 11 | return done(err); 12 | } 13 | 14 | this.webapp = helpers.createGenerator('gulp-webapp:app', [ 15 | '../../app', [ 16 | helpers.createDummyGenerator(), 17 | 'mocha:app' 18 | ] 19 | ]); 20 | this.webapp.options['skip-install'] = true; 21 | 22 | done(); 23 | }.bind(this)); 24 | }); 25 | 26 | var assertFileExists = function (app, fileExt, features, done) { 27 | var expected = [ 28 | 'app/styles/main.' + fileExt 29 | ]; 30 | 31 | helpers.mockPrompt(app, { 32 | features: features 33 | }); 34 | 35 | app.run({}, function () { 36 | helpers.assertFile(expected); 37 | done(); 38 | }); 39 | }; 40 | 41 | it('should create scss file', function (done) { 42 | // assertFileExists(this.webapp, 'scss', ['includeSass'], done); 43 | }); 44 | 45 | it('should create css file', function (done) { 46 | assertFileExists(this.webapp, 'css', [], done); 47 | }); 48 | 49 | }); 50 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | var path = require('path'); 4 | var helpers = require('yeoman-generator').test; 5 | 6 | describe('Gulp webapp generator test', function () { 7 | beforeEach(function (done) { 8 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 9 | if (err) { 10 | return done(err); 11 | } 12 | 13 | this.webapp = helpers.createGenerator('gulp-webapp:app', [ 14 | '../../app', [ 15 | helpers.createDummyGenerator(), 16 | 'mocha:app' 17 | ] 18 | ]); 19 | this.webapp.options['skip-install'] = true; 20 | 21 | done(); 22 | }.bind(this)); 23 | }); 24 | 25 | it('the generator can be required without throwing', function () { 26 | // not testing the actual run of generators yet 27 | this.app = require('../app'); 28 | }); 29 | 30 | it('creates expected files', function (done) { 31 | var expected = [ 32 | 'bower.json', 33 | 'package.json', 34 | 'gulpfile.js', 35 | 'app/404.html', 36 | 'app/favicon.ico', 37 | 'app/robots.txt', 38 | 'app/index.html', 39 | 'app/scripts/main.js' 40 | ]; 41 | 42 | helpers.mockPrompt(this.webapp, { 43 | // features: ['includeSass'] 44 | }); 45 | 46 | this.webapp.run({}, function () { 47 | helpers.assertFile(expected); 48 | done(); 49 | }); 50 | }); 51 | }); 52 | --------------------------------------------------------------------------------