├── .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 | 
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 | 
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 |
37 |
38 |
39 |
Congratulations!
40 |
The bourbon-neat generator has given you...
41 |
42 |
HTML5 Boilerplate is a professional front-end template for building fast, robust, and adaptable web apps or sites.
43 |
44 |
45 |
Sass is a mature, stable, and powerful professional grade CSS extension language.
46 |
47 |
48 |
A simple and lightweight mixin library for Sass.
49 |
50 |
51 |
Sleek, intuitive, and powerful mobile first front-end framework (Grid) for faster and easier web development.
52 |
53 | <% if (includeNormalize) { %>
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) { %>
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 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
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 |
--------------------------------------------------------------------------------