├── .gitattributes ├── app ├── templates │ ├── gitattributes │ ├── robots.txt │ ├── favicon.ico │ ├── gitignore │ ├── apple-touch-icon.png │ ├── editorconfig │ ├── _bower.json │ ├── jshintrc │ ├── main.scss │ ├── _package.json │ ├── index.html │ ├── 404.html │ ├── Gruntfile.js │ └── htaccess ├── USAGE └── index.js ├── .gitignore ├── .travis.yml ├── .editorconfig ├── test ├── test-load.js └── test-creation.js ├── .jshintrc ├── package.json ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /app/templates/gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | temp/ 3 | *.sublime* -------------------------------------------------------------------------------- /app/templates/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /app/templates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koolth/generator-bourbon-neat/HEAD/app/templates/favicon.ico -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | bower_components 6 | test/bower_components 7 | -------------------------------------------------------------------------------- /app/templates/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koolth/generator-bourbon-neat/HEAD/app/templates/apple-touch-icon.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | before_install: 5 | - currentfolder=${PWD##*/} 6 | - if [ "$currentfolder" != 'generator-bourbon-neat' ]; then cd .. && eval "mv $currentfolder generator-bourbon-neat" && cd generator-bourbon-neat; fi 7 | 8 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /app/templates/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 | -------------------------------------------------------------------------------- /test/test-load.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | var assert = require('assert'); 4 | 5 | describe('bourbon-neat generator', function () { 6 | it('can be imported without blowing up', function () { 7 | var app = require('../app'); 8 | assert(app !== undefined); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appName) %>", 3 | "private": true, 4 | "version": "0.0.1", 5 | "dependencies": {<% if (includeModernizr) { %> 6 | "modernizr": "~2.8.3",<% } if (includeNormalize) { %> 7 | "normalize-css": "~3.0.3",<% } %> 8 | "neat": "~1.7.2", 9 | "jquery": "~1.11.2" 10 | }, 11 | "devDependencies": {} 12 | } 13 | 14 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /app/templates/jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": true, 5 | "camelcase": true, 6 | "curly": true, 7 | "eqeqeq": true, 8 | "immed": true, 9 | "indent": 2, 10 | "latedef": true, 11 | "newcap": true, 12 | "noarg": true, 13 | "quotmark": "single", 14 | "regexp": true, 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "white": true 21 | } 22 | -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new front-end web application based on Bourbon Neat (lightweight, semantic Sass grid). 3 | 4 | Options: 5 | Normalize: Include Normalize-css (alternative reset) 6 | Modernizer: Include Modernizer.js 7 | 8 | Example: 9 | yo bourbon-neat 10 | 11 | This will create: 12 | Gruntfile.js: Configuration for the task runner. 13 | bower.json: Front-end packages installed by bower. 14 | package.json: Development packages installed by npm. 15 | 16 | app/: Your application files. 17 | test/: Unit tests for your application. 18 | -------------------------------------------------------------------------------- /test/test-creation.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it */ 2 | 'use strict'; 3 | var path = require('path'); 4 | var helpers = require('yeoman-generator').test; 5 | 6 | describe('bourbon-neat generator', 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.app = helpers.createGenerator('bourbon-neat:app', [ 14 | '../../app' 15 | ]); 16 | done(); 17 | }.bind(this)); 18 | }); 19 | 20 | it('creates expected files', function (done) { 21 | var expected = [ 22 | // add files you expect to exist here. 23 | '.jshintrc', 24 | '.editorconfig' 25 | ]; 26 | 27 | helpers.mockPrompt(this.app, { 28 | 'someOption': true 29 | }); 30 | this.app.options['skip-install'] = true; 31 | this.app.run({}, function () { 32 | helpers.assertFile(expected); 33 | done(); 34 | }); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-bourbon-neat", 3 | "version": "0.1.2", 4 | "description": "Yeoman generator for a website using thoughtbot's Bourbon Neat.", 5 | "license": "MIT", 6 | "main": "app/index.js", 7 | "repository": { 8 | "type": "git", 9 | "url": "koolth/generator-bourbon-neat" 10 | }, 11 | "author": { 12 | "name": "John Flackett", 13 | "email": "", 14 | "url": "https://github.com/koolth" 15 | }, 16 | "engines": { 17 | "node": ">=0.10.0" 18 | }, 19 | "scripts": { 20 | "test": "mocha" 21 | }, 22 | "files": [ 23 | "app" 24 | ], 25 | "keywords": [ 26 | "yeoman", 27 | "yeoman-generator", 28 | "yo", 29 | "thoughtbot", 30 | "bourbon", 31 | "neat", 32 | "sass", 33 | "html", 34 | "html5", 35 | "normalize", 36 | "modernizr", 37 | "website", 38 | "development" 39 | ], 40 | "dependencies": { 41 | "yeoman-generator": "~0.18.10", 42 | "chalk": "~1.0.0", 43 | "yosay": "~1.0.3" 44 | }, 45 | "devDependencies": { 46 | "mocha": "*" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 koolth pty ltd 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. -------------------------------------------------------------------------------- /app/templates/main.scss: -------------------------------------------------------------------------------- 1 | // bower:scss 2 | @import 'bourbon'; 3 | @import 'neat'; 4 | // endbower 5 | 6 | $linkColor: #4183C4; 7 | $hoverColor: lighten($linkColor, 10); 8 | $borderColor: #b3b3b3; 9 | 10 | body { 11 | @include outer-container; 12 | font-family: $helvetica; 13 | background-color: #f0f0f0; 14 | } 15 | .container { 16 | @include span-columns(8); 17 | @include shift(2); 18 | @include margin(25px null 25px null); 19 | padding: 20px; 20 | @include border-top-radius(5px); 21 | @include border-bottom-radius(5px); 22 | border: 1px solid $borderColor; 23 | box-shadow: 0 1px 10px #a7a7a7, inset 0 1px 0 #fff; 24 | background-color: white; 25 | .main { 26 | margin-bottom: 25px; 27 | } 28 | } 29 | .header { 30 | @include span-columns(3); 31 | @include shift(9); 32 | text-align: right; 33 | } 34 | .footer { 35 | @include span-columns(12); 36 | padding: 10px; 37 | font-size: em(14); 38 | color: grey; 39 | text-align: center; 40 | a { 41 | color: #0081C6; 42 | &:hover { 43 | color: $hoverColor; 44 | } 45 | } 46 | } 47 | a { 48 | color: $linkColor; 49 | text-decoration: none; 50 | &:hover { 51 | color: $hoverColor; 52 | } 53 | } 54 | h3 { 55 | margin-bottom: 0; 56 | } 57 | p { 58 | margin-top: 5px; 59 | } -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appName) %>", 3 | "description": "<%= appDescription %>", 4 | "version": "0.0.1", 5 | "author": "<%= authorName %>", 6 | "repository": {}, 7 | "dependencies": {}, 8 | "devDependencies": { 9 | "grunt": "^0.4.5", 10 | "grunt-autoprefixer": "^2.2.0", 11 | "grunt-concurrent": "^1.0.0", 12 | "grunt-contrib-clean": "^0.6.0", 13 | "grunt-contrib-concat": "^0.5.1", 14 | "grunt-contrib-connect": "^0.9.0", 15 | "grunt-contrib-copy": "^0.8.0", 16 | "grunt-contrib-cssmin": "^0.12.2", 17 | "grunt-contrib-htmlmin": "^0.4.0", 18 | "grunt-contrib-imagemin": "^0.9.4", 19 | "grunt-contrib-jshint": "^0.11.1", 20 | "grunt-contrib-sass": "^0.9.2", 21 | "grunt-contrib-uglify": "^0.8.1", 22 | "grunt-contrib-watch": "^0.6.1", 23 | "grunt-mocha": "^0.4.12",<% if (includeModernizr) { %> 24 | "grunt-modernizr": "^0.6.0",<% } %> 25 | "grunt-newer": "^1.1.0", 26 | "grunt-rev": "^0.1.0", 27 | "grunt-svgmin": "^2.0.1", 28 | "grunt-usemin": "^3.0.0", 29 | "grunt-wiredep": "^2.0.0", 30 | "jshint-stylish": "^1.0.1", 31 | "load-grunt-tasks": "^3.1.0", 32 | "time-grunt": "^1.1.0" 33 | }, 34 | "engines": { 35 | "node": ">=0.10.0" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Yeoman Bourbon Neat Generator 2 | 3 | > [Yeoman](http://yeoman.io) generator for Bourbon Neat. 4 | 5 | 6 | ## Getting Started 7 | 8 | ![image](http://koolth.com.au/yo-bourbon-neat.jpg) 9 | 10 | ### generator-bourbon-neat 11 | An easy and straight-forward generator to get you up and running with a full web framework using [Bourbon](http://bourbon.io/) and [Neat](http://neat.bourbon.io/). The generator installs Sass, Bourbon and Neat and gives an [HTML5 Boilerplate](http://html5boilerplate.com/) (it also auto generates a useful directory structure for a web project). 12 | 13 | ###### Optional: 14 | The generator also gives you options for installing [Normalize.css](http://necolas.github.io/normalize.css/) and [Modernizr](http://modernizr.com/) 15 | 16 | Please let us know if you have any difficulties and comments/suggestions. 17 | 18 | ### What is Yeoman? 19 | 20 | Trick question. It's not a thing. It's this guy: 21 | 22 | ![](http://i.imgur.com/JHaAlBJ.png) 23 | 24 | Basically, he wears a top hat, lives in your computer, and waits for you to tell him what kind of application you wish to create. 25 | 26 | Not every new computer comes with a Yeoman pre-installed. He lives in the [npm](https://npmjs.org) package repository. You only have to ask for him once, then he packs up and moves into your hard drive. *Make sure you clean up, he likes new and shiny things.* 27 | 28 | ```bash 29 | $ npm install -g yo 30 | ``` 31 | 32 | ### Yeoman Generators 33 | 34 | Yeoman travels light. He didn't pack any generators when he moved in. You can think of a generator like a plug-in. You get to choose what type of application you wish to create, such as a Backbone application or even a Chrome extension. 35 | 36 | To install generator-bourbon-neat from npm, run: 37 | 38 | ```bash 39 | $ npm install -g generator-bourbon-neat 40 | ``` 41 | 42 | Finally, initiate the generator: 43 | 44 | ```bash 45 | $ yo bourbon-neat 46 | ``` 47 | 48 | ### Getting To Know Yeoman 49 | 50 | Yeoman has a heart of gold. He's a person with feelings and opinions, but he's very easy to work with. If you think he's too opinionated, he can be easily convinced. 51 | 52 | If you'd like to get to know Yeoman better and meet some of his friends, [Grunt](http://gruntjs.com) and [Bower](http://bower.io), check out the complete [Getting Started Guide](https://github.com/yeoman/yeoman/wiki/Getting-Started). 53 | 54 | 55 | **Please note that this generator was originally a cut-down version of a more comprehensive workflow that we used internally within koolth. Over the last year or so we've gradually updated our workflow to a more npm-centric process (i.e., removing grunt). This means we're no longer actively maintaining this repo - however, it will still give you a really good base to get a bourbon/neat HTML project up and running.** 56 | 57 | **Feel free to keep adding issues along with any solutions to help others out.** 58 | 59 | ## License 60 | 61 | MIT 62 | ======= 63 | generator-bourbon-neat 64 | ====================== 65 | 66 | Yeoman generator for a website using thoughtbot's Bourbon Neat. Options for Normalize and Modernizr! 67 | 68 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var yeoman = require('yeoman-generator'); 5 | var yosay = require('yosay'); 6 | var chalk = require('chalk'); 7 | 8 | module.exports = yeoman.generators.Base.extend({ 9 | initializing: function () { 10 | this.pkg = require('../package.json'); 11 | }, 12 | 13 | prompting: function () { 14 | var done = this.async(); 15 | 16 | // Have Yeoman greet the user. 17 | // welcome message 18 | if (!this.options['skip-welcome-message']) { 19 | this.log(yosay('koolth is proud to give you the marvellous Bourbon-Neat web app generator!')); 20 | this.log(chalk.red( 21 | '\nI\'ll give you HTML5 Boilerplate, Bourbon, Neat, Sass, jQuery, and a ' + 22 | 'Gruntfile.js to build your app.' 23 | )); 24 | this.log(chalk.green( 25 | 'You\'ll also have the option to use Normalise-css and Modernizr.js :)\n' 26 | )); 27 | } 28 | 29 | var prompts = [{ 30 | name: 'appName', 31 | message: 'What\'s the name/title of your website?', 32 | default: 'Neat Website' 33 | },{ 34 | name: 'appDescription', 35 | message: 'Short description of the project...', 36 | default: 'A new Neat Website' 37 | },{ 38 | name: 'authorName', 39 | message: 'What\'s your name (the author)?', 40 | default: '' 41 | },{ 42 | type: 'confirm', 43 | name: 'includeNormalize', 44 | message: 'Would you like to include Normalize.css?', 45 | default: true 46 | },{ 47 | type: 'confirm', 48 | name: 'includeModernizr', 49 | message: 'Would you like to include Modernizr.js?', 50 | default: true 51 | }]; 52 | 53 | this.prompt(prompts, function (props) { 54 | this.appName = props.appName; 55 | this.appDescription = props.appDescription; 56 | this.authorName = props.authorName; 57 | this.includeNormalize = props.includeNormalize; 58 | this.includeModernizr = props.includeModernizr; 59 | 60 | done(); 61 | }.bind(this)); 62 | }, 63 | 64 | writing: { 65 | scaffoldDirectories: function(){ 66 | this.mkdir('app'); 67 | this.mkdir('app/sass'); 68 | this.mkdir('app/scripts'); 69 | this.mkdir('app/styles'); 70 | this.mkdir('app/styles/fonts'); 71 | this.mkdir('app/images'); 72 | }, 73 | 74 | app: function () { 75 | this.template('index.html', 'app/index.html'); 76 | this.template('404.html', 'app/404.html'); 77 | this.template('_package.json', 'package.json'); 78 | this.template('_bower.json', 'bower.json'); 79 | this.template('Gruntfile.js', 'Gruntfile.js'); 80 | 81 | this.copy('main.scss', 'app/sass/main.scss'); 82 | this.copy('favicon.ico', 'app/favicon.ico'); 83 | this.copy('htaccess', 'app/.htaccess'); 84 | this.copy('robots.txt', 'app/robots.txt'); 85 | }, 86 | 87 | projectfiles: function () { 88 | this.copy('editorconfig', '.editorconfig'); 89 | this.copy('jshintrc', '.jshintrc'); 90 | this.copy('gitignore', '.gitignore'); 91 | this.copy('gitattributes', '.gitattributes'); 92 | } 93 | }, 94 | 95 | install: function () { 96 | this.installDependencies({ 97 | skipInstall: this.options['skip-install'] 98 | }); 99 | } 100 | }); 101 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= appName %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | <% if (includeNormalize) { %><% } %> 17 | 18 | 19 | 20 | 21 | <% if (includeModernizr) { %> 22 | 23 | 24 | 25 | <% } %> 26 | 27 | 28 | 31 | 32 | 33 |
34 |
35 | 404 Page 36 |
37 | 38 |
39 |

Congratulations!

40 |

The bourbon-neat generator has given you...

41 |

HTML5 Boilerplate

42 |

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

43 | 44 |

Sass

45 |

Sass is a mature, stable, and powerful professional grade CSS extension language.

46 | 47 |

Bourbon

48 |

A simple and lightweight mixin library for Sass.

49 | 50 |

Neat

51 |

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

52 | 53 | <% if (includeNormalize) { %>

Normalize.css

54 |

A modern, HTML5-ready alternative to CSS resets. Makes browsers render all elements more consistently and in line with modern standards.

55 | <% } %> 56 | 57 | <% if (includeModernizr) { %>

Modernizr.js

58 |

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

59 | <% } %> 60 | 61 |

Happy coding!

62 |
63 | 64 |
65 | 66 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /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/Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function (grunt) { 11 | 12 | // Load grunt tasks automatically 13 | require('load-grunt-tasks')(grunt); 14 | 15 | // Time how long tasks take. Can help when optimizing build times 16 | require('time-grunt')(grunt); 17 | 18 | // Configurable paths 19 | var config = { 20 | app: 'app', 21 | dist: 'dist' 22 | }; 23 | 24 | // Define the configuration for all the tasks 25 | grunt.initConfig({ 26 | 27 | // Project settings 28 | config: config, 29 | 30 | // Watches files for changes and runs tasks based on the changed files 31 | watch: { 32 | bower: { 33 | files: ['bower.json'], 34 | tasks: ['bowerInstall'] 35 | }, 36 | js: { 37 | files: ['<%%= config.app %>/scripts/{,*/}*.js'], 38 | tasks: ['jshint'], 39 | options: { 40 | livereload: true 41 | } 42 | }, 43 | jstest: { 44 | files: ['test/spec/{,*/}*.js'], 45 | tasks: ['test:watch'] 46 | }, 47 | gruntfile: { 48 | files: ['Gruntfile.js'] 49 | }, 50 | sass: { 51 | files: ['<%%= config.app %>/sass/{,*/}*.{scss,sass}'], 52 | tasks: ['sass:server', 'autoprefixer'] 53 | }, 54 | styles: { 55 | files: ['<%%= config.app %>/styles/{,*/}*.css'], 56 | tasks: ['newer:copy:styles', 'autoprefixer'] 57 | }, 58 | livereload: { 59 | options: { 60 | livereload: '<%%= connect.options.livereload %>' 61 | }, 62 | files: [ 63 | '<%%= config.app %>/{,*/}*.html', 64 | '.tmp/styles/{,*/}*.css', 65 | '<%%= config.app %>/images/{,*/}*' 66 | ] 67 | } 68 | }, 69 | 70 | // The actual grunt server settings 71 | connect: { 72 | options: { 73 | port: 9000, 74 | open: true, 75 | livereload: 35729, 76 | // Change this to '0.0.0.0' to access the server from outside 77 | hostname: 'localhost' 78 | }, 79 | livereload: { 80 | options: { 81 | middleware: function(connect) { 82 | return [ 83 | connect.static('.tmp'), 84 | connect().use('/bower_components', connect.static('./bower_components')), 85 | connect.static(config.app) 86 | ]; 87 | } 88 | } 89 | }, 90 | test: { 91 | options: { 92 | open: false, 93 | port: 9001, 94 | middleware: function(connect) { 95 | return [ 96 | connect.static('.tmp'), 97 | connect.static('test'), 98 | connect().use('/bower_components', connect.static('./bower_components')), 99 | connect.static(config.app) 100 | ]; 101 | } 102 | } 103 | }, 104 | dist: { 105 | options: { 106 | base: '<%%= config.dist %>', 107 | livereload: false 108 | } 109 | } 110 | }, 111 | 112 | // Empties folders to start fresh 113 | clean: { 114 | dist: { 115 | files: [{ 116 | dot: true, 117 | src: [ 118 | '.tmp', 119 | '<%%= config.dist %>/*', 120 | '!<%%= config.dist %>/.git*' 121 | ] 122 | }] 123 | }, 124 | server: '.tmp' 125 | }, 126 | 127 | // Make sure code styles are up to par and there are no obvious mistakes 128 | jshint: { 129 | options: { 130 | jshintrc: '.jshintrc', 131 | reporter: require('jshint-stylish') 132 | }, 133 | all: [ 134 | 'Gruntfile.js', 135 | '<%%= config.app %>/scripts/{,*/}*.js', 136 | '!<%%= config.app %>/scripts/vendor/*', 137 | 'test/spec/{,*/}*.js' 138 | ] 139 | }, 140 | 141 | // Mocha testing framework configuration options 142 | mocha: { 143 | all: { 144 | options: { 145 | run: true, 146 | urls: ['http://<%%= connect.options.hostname %>:<%%= connect.test.options.port %>/index.html'] 147 | } 148 | } 149 | }, 150 | 151 | // Compiles Sass to CSS and generates necessary files if requested 152 | sass: { 153 | options: { 154 | loadPath: [ 155 | 'bower_components/bourbon/app/assets/stylesheets/', 156 | 'bower_components/neat/app/assets/stylesheets/' 157 | ] 158 | }, 159 | dist: { 160 | files: [{ 161 | expand: true, 162 | cwd: '<%%= config.app %>/sass', 163 | src: ['*.scss'], 164 | dest: '.tmp/styles', 165 | ext: '.css' 166 | }] 167 | }, 168 | server: { 169 | files: [{ 170 | expand: true, 171 | cwd: '<%%= config.app %>/sass', 172 | src: ['*.scss'], 173 | dest: '.tmp/styles', 174 | ext: '.css' 175 | }] 176 | } 177 | }, 178 | 179 | // Add vendor prefixed styles 180 | autoprefixer: { 181 | options: { 182 | browsers: ['last 1 version'] 183 | }, 184 | dist: { 185 | files: [{ 186 | expand: true, 187 | cwd: '.tmp/styles/', 188 | src: '{,*/}*.css', 189 | dest: '.tmp/styles/' 190 | }] 191 | } 192 | }, 193 | 194 | // Automatically inject Bower components into the HTML file 195 | bowerInstall: { 196 | app: { 197 | src: ['<%%= config.app %>/index.html'] 198 | }, 199 | sass: { 200 | src: ['<%%= config.app %>/sass/{,*/}*.{scss,sass}'] 201 | } 202 | }, 203 | 204 | // Renames files for browser caching purposes 205 | rev: { 206 | dist: { 207 | files: { 208 | src: [ 209 | '<%%= config.dist %>/scripts/{,*/}*.js', 210 | '<%%= config.dist %>/styles/{,*/}*.css', 211 | '<%%= config.dist %>/images/{,*/}*.*', 212 | '<%%= config.dist %>/styles/fonts/{,*/}*.*', 213 | '<%%= config.dist %>/*.{ico,png}' 214 | ] 215 | } 216 | } 217 | }, 218 | 219 | // Reads HTML for usemin blocks to enable smart builds that automatically 220 | // concat, minify and revision files. Creates configurations in memory so 221 | // additional tasks can operate on them 222 | useminPrepare: { 223 | options: { 224 | dest: '<%%= config.dist %>' 225 | }, 226 | html: '<%%= config.app %>/index.html' 227 | }, 228 | 229 | // Performs rewrites based on rev and the useminPrepare configuration 230 | usemin: { 231 | options: { 232 | assetsDirs: ['<%%= config.dist %>', '<%%= config.dist %>/images'] 233 | }, 234 | html: ['<%%= config.dist %>/{,*/}*.html'], 235 | css: ['<%%= config.dist %>/styles/{,*/}*.css'] 236 | }, 237 | 238 | // The following *-min tasks produce minified files in the dist folder 239 | imagemin: { 240 | dist: { 241 | files: [{ 242 | expand: true, 243 | cwd: '<%%= config.app %>/images', 244 | src: '{,*/}*.{gif,jpeg,jpg,png}', 245 | dest: '<%%= config.dist %>/images' 246 | }] 247 | } 248 | }, 249 | 250 | svgmin: { 251 | dist: { 252 | files: [{ 253 | expand: true, 254 | cwd: '<%%= config.app %>/images', 255 | src: '{,*/}*.svg', 256 | dest: '<%%= config.dist %>/images' 257 | }] 258 | } 259 | }, 260 | 261 | htmlmin: { 262 | dist: { 263 | options: { 264 | collapseBooleanAttributes: true, 265 | collapseWhitespace: true, 266 | removeAttributeQuotes: true, 267 | removeCommentsFromCDATA: true, 268 | removeEmptyAttributes: true, 269 | removeOptionalTags: true, 270 | removeRedundantAttributes: true, 271 | useShortDoctype: true 272 | }, 273 | files: [{ 274 | expand: true, 275 | cwd: '<%%= config.dist %>', 276 | src: '{,*/}*.html', 277 | dest: '<%%= config.dist %>' 278 | }] 279 | } 280 | }, 281 | 282 | // By default, your `index.html`'s will take care of 283 | // minification. These next options are pre-configured if you do not wish 284 | // to use the Usemin blocks. 285 | // cssmin: { 286 | // dist: { 287 | // files: { 288 | // '<%%= config.dist %>/styles/main.css': [ 289 | // '.tmp/styles/{,*/}*.css', 290 | // '<%%= config.app %>/styles/{,*/}*.css' 291 | // ] 292 | // } 293 | // } 294 | // }, 295 | // uglify: { 296 | // dist: { 297 | // files: { 298 | // '<%%= config.dist %>/scripts/scripts.js': [ 299 | // '<%%= config.dist %>/scripts/scripts.js' 300 | // ] 301 | // } 302 | // } 303 | // }, 304 | // concat: { 305 | // dist: {} 306 | // }, 307 | 308 | // Copies remaining files to places other tasks can use 309 | copy: { 310 | dist: { 311 | files: [{ 312 | expand: true, 313 | dot: true, 314 | cwd: '<%%= config.app %>', 315 | dest: '<%%= config.dist %>', 316 | src: [ 317 | '*.{ico,png,txt}', 318 | '.htaccess', 319 | 'images/{,*/}*.webp', 320 | '{,*/}*.html', 321 | 'styles/fonts/{,*/}*.*' 322 | ] 323 | }] 324 | }, 325 | styles: { 326 | expand: true, 327 | dot: true, 328 | cwd: '<%%= config.app %>/styles', 329 | dest: '.tmp/styles/', 330 | src: '{,*/}*.css' 331 | } 332 | },<% if (includeModernizr) { %> 333 | 334 | // Generates a custom Modernizr build that includes only the tests you 335 | // reference in your app 336 | modernizr: { 337 | dist: { 338 | devFile: 'bower_components/modernizr/modernizr.js', 339 | outputFile: '<%%= config.dist %>/scripts/vendor/modernizr.js', 340 | files: { 341 | src: [ 342 | '<%%= config.dist %>/scripts/{,*/}*.js', 343 | '<%%= config.dist %>/styles/{,*/}*.css', 344 | '!<%%= config.dist %>/scripts/vendor/*' 345 | ] 346 | }, 347 | uglify: true 348 | } 349 | },<% } %> 350 | 351 | // Run some tasks in parallel to speed up build process 352 | concurrent: { 353 | server: [ 354 | 'sass:server', 355 | 'copy:styles' 356 | ], 357 | test: [ 358 | 'copy:styles' 359 | ], 360 | dist: [ 361 | 'sass', 362 | 'copy:styles', 363 | 'imagemin', 364 | 'svgmin' 365 | ] 366 | } 367 | }); 368 | 369 | 370 | grunt.registerTask('serve', function (target) { 371 | if (target === 'dist') { 372 | return grunt.task.run(['build', 'connect:dist:keepalive']); 373 | } 374 | 375 | grunt.task.run([ 376 | 'clean:server', 377 | 'concurrent:server', 378 | 'autoprefixer', 379 | 'connect:livereload', 380 | 'watch' 381 | ]); 382 | }); 383 | 384 | grunt.registerTask('server', function (target) { 385 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.'); 386 | grunt.task.run([target ? ('serve:' + target) : 'serve']); 387 | }); 388 | 389 | grunt.registerTask('test', function (target) { 390 | if (target !== 'watch') { 391 | grunt.task.run([ 392 | 'clean:server', 393 | 'concurrent:test', 394 | 'autoprefixer' 395 | ]); 396 | } 397 | 398 | grunt.task.run([ 399 | 'connect:test', 400 | 'mocha' 401 | ]); 402 | }); 403 | 404 | grunt.registerTask('build', [ 405 | 'clean:dist', 406 | 'useminPrepare', 407 | 'concurrent:dist', 408 | 'autoprefixer', 409 | 'concat', 410 | 'cssmin', 411 | 'copy:dist',<% if (includeModernizr) { %> 412 | 'modernizr',<% } %> 413 | 'rev', 414 | 'usemin', 415 | 'htmlmin' 416 | ]); 417 | 418 | grunt.registerTask('default', [ 419 | 'newer:jshint', 420 | 'test', 421 | 'build' 422 | ]); 423 | }; 424 | -------------------------------------------------------------------------------- /app/templates/htaccess: -------------------------------------------------------------------------------- 1 | # Apache Server Configs v2.3.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 cross-origin data 387 | # leaks, and should be left uncommented, especially if the web server is 388 | # serving user-uploaded content or content that could potentially be treated 389 | # as executable by the browser. 390 | 391 | # http://www.slideshare.net/hasegawayosuke/owasp-hasegawa 392 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx 393 | # http://msdn.microsoft.com/en-us/library/ie/gg622941.aspx 394 | # http://mimesniff.spec.whatwg.org/ 395 | 396 | 397 | Header set X-Content-Type-Options "nosniff" 398 | 399 | 400 | # ------------------------------------------------------------------------------ 401 | # | Reflected Cross-Site Scripting (XSS) attacks | 402 | # ------------------------------------------------------------------------------ 403 | 404 | # (1) Try to re-enable the Cross-Site Scripting (XSS) filter built into the 405 | # most recent web browsers. 406 | # 407 | # The filter is usually enabled by default, but in some cases it may be 408 | # disabled by the user. However, in Internet Explorer for example, it can 409 | # be re-enabled just by sending the `X-XSS-Protection` header with the 410 | # value of `1`. 411 | # 412 | # (2) Prevent web browsers from rendering the web page if a potential reflected 413 | # (a.k.a non-persistent) XSS attack is detected by the filter. 414 | # 415 | # By default, if the filter is enabled and browsers detect a reflected 416 | # XSS attack, they will attempt to block the attack by making the smallest 417 | # possible modifications to the returned web page. 418 | # 419 | # Unfortunately, in some browsers (e.g.: Internet Explorer), this default 420 | # behavior may allow the XSS filter to be exploited, thereby, it's better 421 | # to tell browsers to prevent the rendering of the page altogether, instead 422 | # of attempting to modify it. 423 | # 424 | # http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities 425 | # 426 | # IMPORTANT: Do not rely on the XSS filter to prevent XSS attacks! Ensure that 427 | # you are taking all possible measures to prevent XSS attacks, the most obvious 428 | # being: validating and sanitizing your site's inputs. 429 | # 430 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx 431 | # http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx 432 | # https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 433 | 434 | # 435 | # # (1) (2) 436 | # Header set X-XSS-Protection "1; mode=block" 437 | # 438 | # Header unset X-XSS-Protection 439 | # 440 | # 441 | 442 | # ------------------------------------------------------------------------------ 443 | # | Secure Sockets Layer (SSL) | 444 | # ------------------------------------------------------------------------------ 445 | 446 | # Rewrite secure requests properly in order to prevent SSL certificate warnings. 447 | # E.g.: prevent `https://www.example.com` when your certificate only allows 448 | # `https://secure.example.com`. 449 | 450 | # 451 | # RewriteCond %{SERVER_PORT} !^443 452 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 453 | # 454 | 455 | # ------------------------------------------------------------------------------ 456 | # | HTTP Strict Transport Security (HSTS) | 457 | # ------------------------------------------------------------------------------ 458 | 459 | # Force client-side SSL redirection. 460 | 461 | # If a user types `example.com` in his browser, the above rule will redirect 462 | # him to the secure version of the site. That still leaves a window of 463 | # opportunity (the initial HTTP connection) for an attacker to downgrade or 464 | # redirect the request. 465 | 466 | # The following header ensures that browser will ONLY connect to your server 467 | # via HTTPS, regardless of what the users type in the address bar. 468 | 469 | # http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 470 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 471 | 472 | # IMPORTANT: Remove the `includeSubDomains` optional directive if the subdomains 473 | # are not using HTTPS. 474 | 475 | # 476 | # Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" 477 | # 478 | 479 | # ------------------------------------------------------------------------------ 480 | # | Server software information | 481 | # ------------------------------------------------------------------------------ 482 | 483 | # Avoid displaying the exact Apache version number, the description of the 484 | # generic OS-type and the information about Apache's compiled-in modules. 485 | 486 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 487 | 488 | # ServerTokens Prod 489 | 490 | 491 | # ############################################################################## 492 | # # WEB PERFORMANCE # 493 | # ############################################################################## 494 | 495 | # ------------------------------------------------------------------------------ 496 | # | Compression | 497 | # ------------------------------------------------------------------------------ 498 | 499 | 500 | 501 | # Force compression for mangled headers. 502 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 503 | 504 | 505 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 506 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 507 | 508 | 509 | 510 | # Compress all output labeled with one of the following MIME-types 511 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 512 | # and can remove the `` and `` lines 513 | # as `AddOutputFilterByType` is still in the core directives). 514 | 515 | AddOutputFilterByType DEFLATE application/atom+xml \ 516 | application/javascript \ 517 | application/json \ 518 | application/ld+json \ 519 | application/rss+xml \ 520 | application/vnd.ms-fontobject \ 521 | application/x-font-ttf \ 522 | application/x-web-app-manifest+json \ 523 | application/xhtml+xml \ 524 | application/xml \ 525 | font/opentype \ 526 | image/svg+xml \ 527 | image/x-icon \ 528 | text/css \ 529 | text/html \ 530 | text/plain \ 531 | text/x-component \ 532 | text/xml 533 | 534 | 535 | 536 | 537 | # ------------------------------------------------------------------------------ 538 | # | Content transformations | 539 | # ------------------------------------------------------------------------------ 540 | 541 | # Prevent mobile network providers from modifying the website's content. 542 | # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 543 | 544 | # 545 | # Header set Cache-Control "no-transform" 546 | # 547 | 548 | # ------------------------------------------------------------------------------ 549 | # | ETags | 550 | # ------------------------------------------------------------------------------ 551 | 552 | # Remove `ETags` as resources are sent with far-future expires headers. 553 | # http://developer.yahoo.com/performance/rules.html#etags. 554 | 555 | # `FileETag None` doesn't work in all cases. 556 | 557 | Header unset ETag 558 | 559 | 560 | FileETag None 561 | 562 | # ------------------------------------------------------------------------------ 563 | # | Expires headers | 564 | # ------------------------------------------------------------------------------ 565 | 566 | # The following expires headers are set pretty far in the future. If you 567 | # don't control versioning with filename-based cache busting, consider 568 | # lowering the cache time for resources such as style sheets and JavaScript 569 | # files to something like one week. 570 | 571 | 572 | 573 | ExpiresActive on 574 | ExpiresDefault "access plus 1 month" 575 | 576 | # CSS 577 | ExpiresByType text/css "access plus 1 year" 578 | 579 | # Data interchange 580 | ExpiresByType application/json "access plus 0 seconds" 581 | ExpiresByType application/ld+json "access plus 0 seconds" 582 | ExpiresByType application/xml "access plus 0 seconds" 583 | ExpiresByType text/xml "access plus 0 seconds" 584 | 585 | # Favicon (cannot be renamed!) and cursor images 586 | ExpiresByType image/x-icon "access plus 1 week" 587 | 588 | # HTML components (HTCs) 589 | ExpiresByType text/x-component "access plus 1 month" 590 | 591 | # HTML 592 | ExpiresByType text/html "access plus 0 seconds" 593 | 594 | # JavaScript 595 | ExpiresByType application/javascript "access plus 1 year" 596 | 597 | # Manifest files 598 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 599 | ExpiresByType text/cache-manifest "access plus 0 seconds" 600 | 601 | # Media 602 | ExpiresByType audio/ogg "access plus 1 month" 603 | ExpiresByType image/gif "access plus 1 month" 604 | ExpiresByType image/jpeg "access plus 1 month" 605 | ExpiresByType image/png "access plus 1 month" 606 | ExpiresByType video/mp4 "access plus 1 month" 607 | ExpiresByType video/ogg "access plus 1 month" 608 | ExpiresByType video/webm "access plus 1 month" 609 | 610 | # Web feeds 611 | ExpiresByType application/atom+xml "access plus 1 hour" 612 | ExpiresByType application/rss+xml "access plus 1 hour" 613 | 614 | # Web fonts 615 | ExpiresByType application/font-woff "access plus 1 month" 616 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 617 | ExpiresByType application/x-font-ttf "access plus 1 month" 618 | ExpiresByType font/opentype "access plus 1 month" 619 | ExpiresByType image/svg+xml "access plus 1 month" 620 | 621 | 622 | 623 | # ------------------------------------------------------------------------------ 624 | # | Filename-based cache busting | 625 | # ------------------------------------------------------------------------------ 626 | 627 | # If you're not using a build process to manage your filename version revving, 628 | # you might want to consider enabling the following directives to route all 629 | # requests such as `/css/style.12345.css` to `/css/style.css`. 630 | 631 | # To understand why this is important and a better idea than `*.css?v231`, read: 632 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 633 | 634 | # 635 | # RewriteCond %{REQUEST_FILENAME} !-f 636 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] 637 | # 638 | 639 | # ------------------------------------------------------------------------------ 640 | # | File concatenation | 641 | # ------------------------------------------------------------------------------ 642 | 643 | # Allow concatenation from within specific style sheets and JavaScript files. 644 | 645 | # e.g.: 646 | # 647 | # If you have the following content in a file 648 | # 649 | # 650 | # 651 | # 652 | # Apache will replace it with the content from the specified files. 653 | 654 | # 655 | # 656 | # Options +Includes 657 | # AddOutputFilterByType INCLUDES application/javascript application/json 658 | # SetOutputFilter INCLUDES 659 | # 660 | # 661 | # Options +Includes 662 | # AddOutputFilterByType INCLUDES text/css 663 | # SetOutputFilter INCLUDES 664 | # 665 | # 666 | --------------------------------------------------------------------------------