├── .gitignore
├── .npmignore
├── app
├── templates
│ ├── bowerrc
│ ├── logo.png
│ ├── favicon.ico
│ ├── robots.txt
│ ├── _bower.json
│ ├── jshintrc
│ ├── editorconfig
│ ├── _package.json
│ ├── 404.html
│ ├── index.html
│ ├── Gruntfile.js
│ └── htaccess
└── index.js
├── logo.png
├── .travis.yml
├── .eslintrc
├── test
├── test-load.js
└── test-creation.js
├── .editorconfig
├── README.md
├── package.json
└── LICENSE
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | temp/
3 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .editorconfig
2 | .travis.yml
3 | .eslintrc
4 | test
5 |
--------------------------------------------------------------------------------
/app/templates/bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roman01la/generator-website/master/logo.png
--------------------------------------------------------------------------------
/app/templates/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roman01la/generator-website/master/app/templates/logo.png
--------------------------------------------------------------------------------
/app/templates/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roman01la/generator-website/master/app/templates/favicon.ico
--------------------------------------------------------------------------------
/app/templates/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org/
2 |
3 | # Allow crawling of all content
4 | User-agent: *
5 | Disallow:
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '0.10'
4 | - '0.12'
5 | - 'io.js'
6 | before_script:
7 | - npm i -g bower
8 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true
4 | },
5 |
6 | "rules": {
7 | "quotes": [2, "single"],
8 | "no-underscore-dangle": false
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/app/templates/_bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= __.slugify(appname) %>",
3 | "version": "0.0.0",
4 | "dependencies": {
5 | "modularized-normalize-scss": "~3.0.3",
6 | "modernizr": "~2.8.3",
7 | "jquery": "~2.1.4"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/test/test-load.js:
--------------------------------------------------------------------------------
1 | /*global describe, it*/
2 | 'use strict';
3 |
4 | var assert = require('assert');
5 |
6 | describe('website generator', function () {
7 |
8 | it('can be imported without blowing up', function () {
9 |
10 | assert(require('../app') !== undefined);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/app/templates/jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "bitwise": true,
6 | "camelcase": true,
7 | "curly": true,
8 | "eqeqeq": true,
9 | "immed": true,
10 | "indent": 2,
11 | "latedef": true,
12 | "newcap": true,
13 | "noarg": true,
14 | "quotmark": "single",
15 | "regexp": true,
16 | "undef": true,
17 | "unused": true,
18 | "strict": true,
19 | "trailing": true,
20 | "smarttabs": true
21 | }
22 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 4
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/app/templates/editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Generator website
2 |
3 | 
4 | [](http://badge.fury.io/js/generator-website)
5 | [](https://travis-ci.org/roman01la/generator-website)
6 | [](https://gemnasium.com/roman01la/generator-website)
7 |
8 | 
9 |
10 | A website generator for Yeoman.
11 |
12 | ## Installation
13 | Make sure you have [yo](https://github.com/yeoman/yo) installed: `npm i -g yo`
14 |
15 | ```
16 | npm i -g generator-website
17 | ```
18 |
19 | ## Usage
20 |
21 | ```
22 | yo website
23 | ```
24 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-website",
3 | "version": "0.2.0",
4 | "description": "A website generator for Yeoman",
5 | "keywords": [
6 | "yeoman-generator"
7 | ],
8 | "homepage": "https://github.com/roman01la/generator-website",
9 | "bugs": "https://github.com/roman01la/generator-website/issues",
10 | "author": {
11 | "name": "roman01la",
12 | "email": "roman01la@romanliutikov.com",
13 | "url": "https://github.com/roman01la"
14 | },
15 | "main": "app/index.js",
16 | "repository": {
17 | "type": "git",
18 | "url": "https://github.com/roman01la/generator-website.git"
19 | },
20 | "scripts": {
21 | "test": "mocha"
22 | },
23 | "dependencies": {
24 | "html-wiring": "^1.1.0",
25 | "lodash": "^3.7.0",
26 | "mkdirp": "^0.5.0",
27 | "yeoman-generator": "~0.19.2"
28 | },
29 | "devDependencies": {
30 | "eslint": "^0.19.0",
31 | "mocha": "~2.2.4"
32 | },
33 | "licenses": [
34 | {
35 | "type": "MIT"
36 | }
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/app/templates/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= __.slugify(appname) %>",
3 | "version": "0.0.0",
4 | "dependencies": {},
5 | "devDependencies": {
6 | "grunt": "~0.4.4",
7 | "grunt-contrib-copy": "~0.5.0",
8 | "grunt-contrib-concat": "~0.4.0",
9 | "grunt-contrib-uglify": "~0.4.0",
10 | "grunt-contrib-compass": "~0.7.2",
11 | "grunt-contrib-jshint": "~0.10.0",
12 | "grunt-contrib-cssmin": "~0.9.0",
13 | "grunt-contrib-connect": "~0.7.1",
14 | "grunt-contrib-clean": "~0.5.0",
15 | "grunt-contrib-htmlmin": "~0.2.0",
16 | "grunt-contrib-imagemin": "~0.6.1",
17 | "grunt-contrib-watch": "~0.6.1",
18 | "grunt-rev": "~0.1.0",
19 | "grunt-usemin": "~2.1.1",
20 | "grunt-svgmin": "~0.4.0",
21 | "grunt-concurrent": "~0.5.0",
22 | "connect-livereload": "~0.3.2",
23 | "load-grunt-tasks": "~0.4.0",
24 | "time-grunt": "~0.3.1",
25 | "grunt-autoprefixer": "~0.7.2",
26 | "jshint-stylish": "~0.1.5"
27 | },
28 | "engines": {
29 | "node": ">=0.10"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/test/test-creation.js:
--------------------------------------------------------------------------------
1 | /*global describe, beforeEach, it*/
2 | 'use strict';
3 |
4 | var path = require('path'),
5 | helpers = require('yeoman-generator').test,
6 | assert = require('yeoman-generator').assert;
7 |
8 |
9 | describe('website generator', function () {
10 |
11 | beforeEach(function (done) {
12 |
13 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) {
14 |
15 | if (err) { return done(err); }
16 |
17 | this.app = helpers.createGenerator('website:app', ['../../app']);
18 |
19 | done();
20 | }.bind(this));
21 | });
22 |
23 | it('creates expected files', function (done) {
24 |
25 | var expected = [
26 |
27 | // add files you expect to exist here.
28 | '.jshintrc',
29 | '.editorconfig'
30 | ];
31 |
32 | helpers.mockPrompt(this.app, {
33 |
34 | 'someOption': 'Y'
35 | });
36 |
37 | this.app.run(function () {
38 |
39 | assert.file(expected);
40 | done();
41 | });
42 | });
43 | });
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Roman Liutikov
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.
22 |
--------------------------------------------------------------------------------
/app/templates/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Page Not Found
6 |
7 |
53 |
54 |
55 | Page Not Found
56 | Sorry, but the page you were trying to view does not exist.
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
22 |
23 |
24 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | var util = require('util'),
4 | path = require('path'),
5 | yeoman = require('yeoman-generator'),
6 | writing = require('html-wiring'),
7 | mkdirp = require('mkdirp');
8 |
9 |
10 | var WebsiteGenerator = module.exports = function WebsiteGenerator (args, options) {
11 |
12 | yeoman.generators.Base.apply(this, arguments);
13 |
14 | this.__ = require('lodash');
15 |
16 | this.indexFile = writing.readFileAsString(path.join(this.sourceRoot(), 'index.html'));
17 |
18 | this.on('end', function() {
19 |
20 | this.installDependencies({ skipInstall: options['skip-install'] });
21 | });
22 |
23 | this.pkg = JSON.parse(writing.readFileAsString(path.join(__dirname, '../package.json')));
24 | };
25 |
26 | util.inherits(WebsiteGenerator, yeoman.generators.NamedBase);
27 |
28 | WebsiteGenerator.prototype.gruntfile = function() {
29 |
30 | this.template('Gruntfile.js');
31 | };
32 |
33 | WebsiteGenerator.prototype.h5bp = function() {
34 |
35 | this.copy('favicon.ico', 'favicon.ico');
36 | this.copy('404.html', '404.html');
37 | this.copy('robots.txt', 'robots.txt');
38 | this.copy('htaccess', '.htaccess');
39 | };
40 |
41 | WebsiteGenerator.prototype.projectFiles = function() {
42 |
43 | this.copy('_package.json', 'package.json');
44 | this.copy('bowerrc', '.bowerrc');
45 | this.copy('_bower.json', 'bower.json');
46 | this.copy('jshintrc', '.jshintrc');
47 | this.copy('editorconfig', '.editorconfig');
48 | };
49 |
50 | WebsiteGenerator.prototype.writeIndex = function() {
51 |
52 | var contentText = [
53 | ' ',
54 | ' Hello World!
',
55 | '
'
56 | ];
57 |
58 | this.indexFile = writing.appendScripts(this.indexFile, 'js/main.js', [
59 |
60 | 'bower_components/jquery/dist/jquery.js',
61 | 'js/script.js'
62 | ]);
63 |
64 | this.indexFile = this.indexFile.replace('', '\n' + contentText.join('\n'));
65 | };
66 |
67 | WebsiteGenerator.prototype.app = function() {
68 |
69 | mkdirp('styles');
70 | mkdirp('js');
71 | mkdirp('img');
72 | this.copy('logo.png', 'img/logo.png');
73 | this.write('index.html', this.indexFile);
74 | this.write('js/script.js', '(function () {\n\n})();');
75 | this.write('styles/main.scss', [
76 |
77 | '@import "modularized-normalize-scss/normalize";',
78 | '\n\n',
79 | 'body {',
80 | ' text-align: center;',
81 | '}'
82 | ].join('\n'));
83 | };
84 |
--------------------------------------------------------------------------------
/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 | grunt.initConfig({
19 |
20 | // Project settings
21 | yeoman: {
22 | // configurable paths
23 | app: require('./bower.json').appPath || '.',
24 | dist: 'dist'
25 | },
26 |
27 | watch: {
28 | compass: {
29 | files: ['<%%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
30 | tasks: ['compass:server', 'autoprefixer']
31 | },
32 | js: {
33 | files: ['<%%= yeoman.app %>/js/{,*/}*.js'],
34 | tasks: ['newer:jshint:all'],
35 | options: {
36 | livereload: true
37 | }
38 | },
39 | livereload: {
40 | options: {
41 | livereload: '<%%= connect.options.livereload %>'
42 | },
43 | files: [
44 | '<%%= yeoman.app %>/*.html',
45 | '.tmp/styles/{,*/}*.css',
46 | '.tmp/js/{,*/}*.js',
47 | '<%%= yeoman.app %>/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
48 | ]
49 | }
50 | },
51 | connect: {
52 | options: {
53 | port: 9000,
54 | // change this to '0.0.0.0' to access the server from outside
55 | hostname: 'localhost',
56 | livereload: 35729
57 | },
58 | livereload: {
59 | options: {
60 | open: true,
61 | base: ['.tmp', '<%%= yeoman.app %>']
62 | }
63 | },
64 | dist: {
65 | options: {
66 | open: true,
67 | base: '<%%= yeoman.dist %>'
68 | }
69 | }
70 | },
71 | clean: {
72 | dist: {
73 | files: [
74 | {
75 | dot: true,
76 | src: [
77 | '.tmp',
78 | '<%%= yeoman.dist %>/*',
79 | '!<%%= yeoman.dist %>/.git*'
80 | ]
81 | }
82 | ]
83 | },
84 | server: '.tmp'
85 | },
86 | jshint: {
87 | options: {
88 | jshintrc: '.jshintrc',
89 | reporter: require('jshint-stylish')
90 | },
91 | all: [
92 | 'Gruntfile.js',
93 | '<%%= yeoman.app %>/js/{,*/}*.js'
94 | ]
95 | },
96 | compass: {
97 | options: {
98 | sassDir: '<%%= yeoman.app %>/styles',
99 | cssDir: '.tmp/styles',
100 | generatedImagesDir: '.tmp/img/generated',
101 | imagesDir: '<%%= yeoman.app %>/img',
102 | javascriptsDir: '<%%= yeoman.app %>/js',
103 | fontsDir: '<%%= yeoman.app %>/styles/fonts',
104 | importPath: '<%%= yeoman.app %>/bower_components',
105 | httpImagesPath: '/img',
106 | httpGeneratedImagesPath: '/img/generated',
107 | httpFontsPath: '/styles/fonts',
108 | relativeAssets: false,
109 | assetCacheBuster: false,
110 | raw: 'Sass::Script::Number.precision = 10\n'
111 | },
112 | dist: {},
113 | server: {
114 | options: {
115 | debugInfo: true
116 | }
117 | }
118 | },
119 | autoprefixer: {
120 | options: {
121 | browsers: ['last 2 versions']
122 | },
123 | dist: {
124 | files: [{
125 | expand: true,
126 | cwd: '.tmp/styles/',
127 | src: '<%%= yeoman.app %>/{,*/}*.css',
128 | dest: '.tmp/styles/'
129 | }]
130 | }
131 | },
132 | // not used since Uglify task does concat,
133 | // but still available if needed
134 | /*concat: {
135 | dist: {}
136 | },*/
137 | // not enabled since usemin task does concat and uglify
138 | // check index.html to edit your build targets
139 | // enable this task if you prefer defining your build targets here
140 | /*uglify: {
141 | dist: {}
142 | },*/
143 | rev: {
144 | dist: {
145 | files: {
146 | src: [
147 | '<%%= yeoman.dist %>/js/{,*/}*.js',
148 | '<%%= yeoman.dist %>/styles/{,*/}*.css',
149 | '<%%= yeoman.dist %>/img/{,*/}*.{png,jpg,jpeg,gif,webp}',
150 | '<%%= yeoman.dist %>/styles/fonts/*'
151 | ]
152 | }
153 | }
154 | },
155 | useminPrepare: {
156 | options: {
157 | dest: '<%%= yeoman.dist %>'
158 | },
159 | html: '<%%= yeoman.app %>/index.html'
160 | },
161 | usemin: {
162 | options: {
163 | assetsDirs: ['<%%= yeoman.dist %>']
164 | },
165 | html: ['<%%= yeoman.dist %>/{,*/}*.html'],
166 | css: ['<%%= yeoman.dist %>/styles/{,*/}*.css']
167 | },
168 | imagemin: {
169 | dist: {
170 | files: [
171 | {
172 | expand: true,
173 | cwd: '<%%= yeoman.app %>/img',
174 | src: '{,*/}*.{png,jpg,jpeg}',
175 | dest: '<%%= yeoman.dist %>/img'
176 | }
177 | ]
178 | }
179 | },
180 | svgmin: {
181 | dist: {
182 | files: [
183 | {
184 | expand: true,
185 | cwd: '<%%= yeoman.app %>/img',
186 | src: '{,*/}*.svg',
187 | dest: '<%%= yeoman.dist %>/img'
188 | }
189 | ]
190 | }
191 | },
192 | cssmin: {
193 | dist: {
194 | files: {
195 | '<%%= yeoman.dist %>/styles/main.css': ['.tmp/styles/{,*/}*.css']
196 | }
197 | }
198 | },
199 | htmlmin: {
200 | dist: {
201 | options: {
202 | /*removeCommentsFromCDATA: true,
203 | // https://github.com/yeoman/grunt-usemin/issues/44
204 | //collapseWhitespace: true,
205 | collapseBooleanAttributes: true,
206 | removeAttributeQuotes: true,
207 | removeRedundantAttributes: true,
208 | useShortDoctype: true,
209 | removeEmptyAttributes: true,
210 | removeOptionalTags: true*/
211 | },
212 | files: [
213 | {
214 | expand: true,
215 | cwd: '<%%= yeoman.app %>',
216 | src: '*.html',
217 | dest: '<%%= yeoman.dist %>'
218 | }
219 | ]
220 | }
221 | },
222 | // Put files not handled in other tasks here
223 | copy: {
224 | dist: {
225 | files: [
226 | {
227 | expand: true,
228 | dot: true,
229 | cwd: '<%%= yeoman.app %>',
230 | dest: '<%%= yeoman.dist %>',
231 | src: [
232 | '*.{ico,txt}',
233 | '.htaccess',
234 | 'img/{,*/}*.{webp,gif}',
235 | 'styles/fonts/*'
236 | ]
237 | },
238 | {
239 | expand: true,
240 | cwd: '.tmp/img',
241 | dest: '<%%= yeoman.dist %>/img',
242 | src: ['generated/*']
243 | }
244 | ]
245 | }
246 | },
247 | concurrent: {
248 | server: [
249 | 'compass:server'
250 | ],
251 | dist: [
252 | 'compass:dist',
253 | 'imagemin',
254 | 'svgmin',
255 | 'htmlmin'
256 | ]
257 | }
258 | });
259 |
260 | grunt.registerTask('serve', function (target) {
261 | if (target === 'dist') {
262 | return grunt.task.run(['build', 'connect:dist:keepalive']);
263 | }
264 |
265 | grunt.task.run([
266 | 'clean:server',
267 | 'concurrent:server',
268 | 'autoprefixer',
269 | 'connect:livereload',
270 | 'watch'
271 | ]);
272 | });
273 |
274 | grunt.registerTask('server', function() {
275 | grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
276 | grunt.task.run(['serve']);
277 | });
278 |
279 | grunt.registerTask('build', [
280 | 'clean:dist',
281 | 'useminPrepare',
282 | 'concurrent:dist',
283 | 'autoprefixer',
284 | 'cssmin',
285 | 'concat',
286 | 'uglify',
287 | 'copy',
288 | 'rev',
289 | 'usemin'
290 | ]);
291 |
292 | grunt.registerTask('default', [
293 | 'jshint',
294 | 'build'
295 | ]);
296 | };
297 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------