├── .npmignore ├── .gitattributes ├── .gitignore ├── app ├── templates │ ├── _env │ ├── app │ │ ├── .buildignore │ │ ├── robots.txt │ │ ├── favicon.ico │ │ ├── views │ │ │ └── main.html │ │ ├── scripts │ │ │ ├── controllers │ │ │ │ └── main.js │ │ │ └── app.js │ │ ├── styles │ │ │ └── main.css │ │ ├── index.html │ │ ├── 404.html │ │ └── .htaccess │ ├── _Procfile │ ├── _gitattributes │ ├── _bowerrc │ ├── _gitignore │ ├── config │ │ └── environments │ │ │ ├── index.js │ │ │ ├── production.js │ │ │ └── development.js │ ├── routes │ │ └── index.js │ ├── public │ │ └── stylesheets │ │ │ └── style.css │ ├── _app_grunt.js │ ├── _server.js │ ├── test │ │ ├── runner.html │ │ └── spec │ │ │ └── controllers │ │ │ └── main.js │ ├── _app.js │ ├── _editorconfig │ ├── _jshintrc │ ├── _bower.json │ ├── views │ │ └── index.ejs │ ├── _karma-e2e.conf.js │ ├── _package.json │ ├── _karma.conf.js │ └── _Gruntfile.js └── index.js ├── .travis.yml ├── .editorconfig ├── test ├── test-load.js └── test-creation.js ├── .jshintrc ├── package.json ├── LICENSE └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | temp/ 3 | -------------------------------------------------------------------------------- /app/templates/_env: -------------------------------------------------------------------------------- 1 | NODE_ENV=production -------------------------------------------------------------------------------- /app/templates/app/.buildignore: -------------------------------------------------------------------------------- 1 | *.coffee -------------------------------------------------------------------------------- /app/templates/_Procfile: -------------------------------------------------------------------------------- 1 | web: node server.js -------------------------------------------------------------------------------- /app/templates/_gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | -------------------------------------------------------------------------------- /app/templates/app/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /app/templates/_bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/_gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | app/bower_components 6 | -------------------------------------------------------------------------------- /app/templates/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wlepinski/generator-meanstack/HEAD/app/templates/app/favicon.ico -------------------------------------------------------------------------------- /app/templates/config/environments/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (app) { 2 | require('./development')(app); 3 | require('./production')(app); 4 | }; 5 | -------------------------------------------------------------------------------- /app/templates/routes/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (app) { 2 | app.get('/', function (req, res, next) { 3 | res.render('index'); 4 | }); 5 | }; 6 | -------------------------------------------------------------------------------- /app/templates/public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /app/templates/_app_grunt.js: -------------------------------------------------------------------------------- 1 | var app = require('./app'); 2 | 3 | module.exports = require('http').createServer(app); 4 | module.exports.express = app; 5 | module.exports.use = function() { 6 | app.use.apply(app, arguments); 7 | }; 8 | -------------------------------------------------------------------------------- /app/templates/_server.js: -------------------------------------------------------------------------------- 1 | var app = require('./app'); 2 | 3 | require('http').createServer(app).listen(app.get('port'), function () { 4 | console.log('Express (' + app.get('env') + ') server listening on port ' + app.get('port')); 5 | }); 6 | -------------------------------------------------------------------------------- /app/templates/app/views/main.html: -------------------------------------------------------------------------------- 1 |
2 |

'Allo, 'Allo!

3 |

You now have

4 | 7 |

installed.

8 |

Enjoy coding! - Yeoman

9 |
10 | -------------------------------------------------------------------------------- /app/templates/test/runner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End2end Test Runner 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/templates/app/scripts/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('<%= _.camelize(appname)%>App') 4 | .controller('MainCtrl', function ($scope) { 5 | $scope.awesomeThings = [ 6 | 'HTML5 Boilerplate', 7 | 'AngularJS', 8 | 'Karma' 9 | ]; 10 | }); 11 | -------------------------------------------------------------------------------- /app/templates/_app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | routes = require('./routes'), 3 | path = require('path'); 4 | 5 | var app = express(); 6 | app.directory = __dirname; 7 | 8 | require('./config/environments')(app); 9 | require('./routes')(app); 10 | 11 | module.exports = app; 12 | -------------------------------------------------------------------------------- /test/test-load.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | 4 | var assert = require('assert'); 5 | 6 | describe('meanstack generator', function () { 7 | it('can be imported without blowing up', function () { 8 | var app = require('../app'); 9 | assert(app !== undefined); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /app/templates/_editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | # Change these settings to your own preference 6 | indent_style = space 7 | indent_size = 4 8 | 9 | # We recommend you to keep these unchanged 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "es5": true, 4 | "esnext": true, 5 | "bitwise": true, 6 | "camelcase": true, 7 | "curly": true, 8 | "eqeqeq": true, 9 | "immed": true, 10 | "indent": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "regexp": true, 16 | "undef": true, 17 | "unused": true, 18 | "strict": true, 19 | "trailing": true, 20 | "smarttabs": true, 21 | "white": true 22 | } 23 | -------------------------------------------------------------------------------- /app/templates/app/styles/main.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #fafafa; 3 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 4 | color: #333; 5 | } 6 | 7 | .hero-unit { 8 | margin: 50px auto 0 auto; 9 | width: 300px; 10 | font-size: 18px; 11 | font-weight: 200; 12 | line-height: 30px; 13 | background-color: #eee; 14 | border-radius: 6px; 15 | padding: 60px; 16 | } 17 | 18 | .hero-unit h1 { 19 | font-size: 60px; 20 | line-height: 1; 21 | letter-spacing: -1px; 22 | } 23 | -------------------------------------------------------------------------------- /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 | "globals": { 22 | "angular": false 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/templates/app/scripts/app.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | (function(){ 3 | <% if (!angularStable) { %> 4 | var app = angular.module('<%= _.camelize(appname)%>App', ['ngRoute']);<% } %> 5 | <% if (angularStable) { %> 6 | var app = angular.module('<%= _.camelize(appname)%>App', []);<% } %> 7 | app.config(function ($routeProvider) { 8 | $routeProvider 9 | .when('/', { 10 | templateUrl: 'views/main.html', 11 | controller: 'MainCtrl' 12 | }) 13 | .otherwise({ 14 | redirectTo: '/' 15 | }); 16 | }); 17 | 18 | }.call(this)); 19 | -------------------------------------------------------------------------------- /app/templates/test/spec/controllers/main.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('Controller: MainCtrl', function () { 4 | 5 | // load the controller's module 6 | beforeEach(module('<%= _.camelize(appname) %>App')); 7 | 8 | var MainCtrl, 9 | scope; 10 | 11 | // Initialize the controller and a mock scope 12 | beforeEach(inject(function ($controller, $rootScope) { 13 | scope = $rootScope.$new(); 14 | MainCtrl = $controller('MainCtrl', { 15 | $scope: scope 16 | }); 17 | })); 18 | 19 | it('should attach a list of awesomeThings to the scope', function () { 20 | expect(scope.awesomeThings.length).toBe(3); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /app/templates/config/environments/production.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | path = require('path'); 3 | 4 | module.exports = function (app) { 5 | app.configure('production', function () { 6 | app.set('port', process.env.PORT || 9000); 7 | app.set('views', path.join(app.directory, '/dist')); 8 | app.engine('html', require('ejs').renderFile); 9 | app.set('view engine', 'html'); 10 | app.use(express.favicon()); 11 | app.use(express.logger('dev')); 12 | app.use(express.bodyParser()); 13 | app.use(express.methodOverride()); 14 | app.use(express.cookieParser('your secret here')); 15 | app.use(express.session()); 16 | app.use(app.router); 17 | app.use(express.static(path.join(app.directory, 'dist'))); 18 | }); 19 | }; 20 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "jquery": "~2.0.3", 6 | "angular": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 7 | "angular-resource": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 8 | "angular-cookies": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 9 | "angular-sanitize": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 10 | <% if (!angularStable) { %> 11 | "angular-route": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 12 | <% } %> 13 | "json3": "~3.2.4", 14 | "es5-shim": "~2.0.8" 15 | }, 16 | "devDependencies": { 17 | "angular-mocks": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %>, 18 | "angular-scenario": <%= (angularStable) ? '"~1.0.8"' : '"1.2.0-rc.3"' %> 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/templates/views/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= title %> 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |

Hello world! This is HTML5 Boilerplate.

20 | 21 | 22 | -------------------------------------------------------------------------------- /test/test-creation.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 'use strict'; 3 | 4 | var path = require('path'); 5 | var helpers = require('yeoman-generator').test; 6 | 7 | 8 | describe('meanstack generator', function () { 9 | beforeEach(function (done) { 10 | helpers.testDirectory(path.join(__dirname, 'temp'), function (err) { 11 | if (err) { 12 | return done(err); 13 | } 14 | 15 | this.app = helpers.createGenerator('meanstack:app', [ 16 | '../../app' 17 | ]); 18 | done(); 19 | }.bind(this)); 20 | }); 21 | 22 | it('creates expected files', function (done) { 23 | var expected = [ 24 | // add files you expect to exist here. 25 | '.jshintrc', 26 | '.editorconfig' 27 | ]; 28 | 29 | helpers.mockPrompt(this.app, { 30 | 'someOption': 'Y' 31 | }); 32 | this.app.options['skip-install'] = true; 33 | this.app.run({}, function () { 34 | helpers.assertFiles(expected); 35 | done(); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-meanstack", 3 | "version": "0.1.1", 4 | "description": "The MEAN stack generator for Yeoman.", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "mongodb", 8 | "angularjs", 9 | "expressjs" 10 | ], 11 | "homepage": "https://github.com/wlepinski/generator-meanstack", 12 | "bugs": "https://github.com/wlepinski/generator-meanstack/issues", 13 | "author": { 14 | "name": "William Albino Lepinski", 15 | "email": "willsp@gmail.com", 16 | "url": "https://github.com/wlepinski" 17 | }, 18 | "main": "app/index.js", 19 | "repository": { 20 | "type": "git", 21 | "url": "git://github.com/wlepinski/generator-meanstack.git" 22 | }, 23 | "scripts": { 24 | "test": "mocha" 25 | }, 26 | "dependencies": { 27 | "yeoman-generator": "~0.15.0" 28 | }, 29 | "devDependencies": { 30 | "mocha": "~1.16.1" 31 | }, 32 | "engines": { 33 | "node": ">=0.10.x" 34 | }, 35 | "licenses": [ 36 | { 37 | "type": "MIT" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /app/templates/config/environments/development.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | path = require('path'); 3 | 4 | module.exports = function (app) { 5 | app.configure('development', function () { 6 | app.use(function staticsPlaceholder(req, res, next) { 7 | return next(); 8 | }); 9 | 10 | app.set('port', process.env.PORT || 9000); 11 | app.set('views', path.join(app.directory, '/app')); 12 | app.engine('html', require('ejs').renderFile); 13 | app.set('view engine', 'html'); 14 | app.use(express.favicon()); 15 | app.use(express.logger('dev')); 16 | app.use(express.bodyParser()); 17 | app.use(express.methodOverride()); 18 | app.use(express.cookieParser('your secret here')); 19 | app.use(express.session()); 20 | 21 | app.use(function middlewarePlaceholder(req, res, next) { 22 | return next(); 23 | }); 24 | 25 | app.use(app.router); 26 | app.use(express.errorHandler()); 27 | }); 28 | }; 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2013 William Albino Lepinski 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Generator-meanstack 2 | [![Build Status](https://secure.travis-ci.org/wlepinski/generator-meanstack.png?branch=master)](https://travis-ci.org/wlepinski/generator-meanstack) 3 | [![NPM version](https://badge.fury.io/js/generator-meanstack.png)](http://badge.fury.io/js/generator-meanstack) 4 | 5 | The MEAN stack generator for Yeoman. 6 | 7 | ## Getting started 8 | - Make sure you have [yo](https://github.com/yeoman/yo) installed on the latest version. 9 | `npm install -g yo` 10 | - Install the generator: `npm install -g generator-meanstack` 11 | - Run: `yo meanstack` 12 | 13 | This generator is based on the [generator-angular](https://github.com/yeoman/generator-angular). 14 | This means that you can use all commands available on the generator-angular to create your application. 15 | 16 | ### Deploying to Heroku 17 | During the scaffold you are able to create Procfile and .env files on your target project. After that follow the steps below. 18 | 19 | 1. Use the command grunt to generate the optimized files for your application. 20 | 2. Set the environment variable NODE_ENV to production before pushing your modifications to Heroku. 21 | 22 | ## License 23 | [MIT License](http://en.wikipedia.org/wiki/MIT_License) 24 | -------------------------------------------------------------------------------- /app/templates/_karma-e2e.conf.js: -------------------------------------------------------------------------------- 1 | // Karma E2E configuration 2 | 3 | // base path, that will be used to resolve files and exclude 4 | basePath = ''; 5 | 6 | // list of files / patterns to load in the browser 7 | files = [ 8 | ANGULAR_SCENARIO, 9 | ANGULAR_SCENARIO_ADAPTER, 10 | 'test/e2e/**/*.js' 11 | ]; 12 | 13 | // list of files to exclude 14 | exclude = []; 15 | 16 | // test results reporter to use 17 | // possible values: dots || progress || growl 18 | reporters = ['progress']; 19 | 20 | // web server port 21 | port = 8080; 22 | 23 | // cli runner port 24 | runnerPort = 9100; 25 | 26 | // enable / disable colors in the output (reporters and logs) 27 | colors = true; 28 | 29 | // level of logging 30 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 31 | logLevel = LOG_INFO; 32 | 33 | // enable / disable watching file and executing tests whenever any file changes 34 | autoWatch = false; 35 | 36 | // Start these browsers, currently available: 37 | // - Chrome 38 | // - ChromeCanary 39 | // - Firefox 40 | // - Opera 41 | // - Safari (only Mac) 42 | // - PhantomJS 43 | // - IE (only Windows) 44 | browsers = ['Chrome']; 45 | 46 | // If browser does not capture in given timeout [ms], kill it 47 | captureTimeout = 5000; 48 | 49 | // Continuous Integration mode 50 | // if true, it capture browsers, run tests and exit 51 | singleRun = false; 52 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node server" 7 | }, 8 | "engines": { 9 | "node": ">=0.8.0" 10 | }, 11 | "dependencies": { 12 | "express": "3.4.0", 13 | "ejs": "*" 14 | }, 15 | "devDependencies": { 16 | "grunt": "~0.4.1", 17 | "grunt-contrib-copy": "~0.4.1", 18 | "grunt-contrib-concat": "~0.3.0", 19 | "grunt-contrib-coffee": "~0.7.0", 20 | "grunt-contrib-uglify": "~0.2.0", 21 | "grunt-contrib-compass": "~0.3.0", 22 | "grunt-contrib-jshint": "~0.6.0", 23 | "grunt-contrib-cssmin": "~0.6.0", 24 | "grunt-contrib-connect": "~0.3.0", 25 | "grunt-contrib-clean": "~0.4.1", 26 | "grunt-contrib-htmlmin": "~0.1.3", 27 | "grunt-contrib-imagemin": "~0.1.4", 28 | "grunt-contrib-watch": "~0.4.0", 29 | "grunt-usemin": "~0.1.11", 30 | "grunt-rev": "~0.1.0", 31 | "grunt-karma": "~0.4.3", 32 | "grunt-open": "~0.2.0", 33 | "grunt-concurrent": "~0.3.0", 34 | "matchdep": "~0.1.2", 35 | "connect-livereload": "~0.2.0", 36 | "grunt-google-cdn": "~0.2.0", 37 | "grunt-ngmin": "~0.0.2", 38 | "grunt-express": "~1.2.1", 39 | "time-grunt": "~0.1.1" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/templates/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | <% if (!angularStable) { %> 23 | 24 | <% } %> 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/templates/_karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | 3 | // base path, that will be used to resolve files and exclude 4 | basePath = ''; 5 | 6 | // list of files / patterns to load in the browser 7 | files = [ 8 | JASMINE, 9 | JASMINE_ADAPTER, 10 | 'app/bower_components/angular/angular.js', 11 | 'app/bower_components/angular-mocks/angular-mocks.js', 12 | 'app/scripts/*.js', 13 | 'app/scripts/**/*.js', 14 | 'test/mock/**/*.js', 15 | 'test/spec/**/*.js' 16 | ]; 17 | 18 | // list of files to exclude 19 | exclude = []; 20 | 21 | // test results reporter to use 22 | // possible values: dots || progress || growl 23 | reporters = ['progress']; 24 | 25 | // web server port 26 | port = 8080; 27 | 28 | // cli runner port 29 | runnerPort = 9100; 30 | 31 | // enable / disable colors in the output (reporters and logs) 32 | colors = true; 33 | 34 | // level of logging 35 | // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG 36 | logLevel = LOG_INFO; 37 | 38 | // enable / disable watching file and executing tests whenever any file changes 39 | autoWatch = false; 40 | 41 | // Start these browsers, currently available: 42 | // - Chrome 43 | // - ChromeCanary 44 | // - Firefox 45 | // - Opera 46 | // - Safari (only Mac) 47 | // - PhantomJS 48 | // - IE (only Windows) 49 | browsers = ['Chrome']; 50 | 51 | // If browser does not capture in given timeout [ms], kill it 52 | captureTimeout = 5000; 53 | 54 | // Continuous Integration mode 55 | // if true, it capture browsers, run tests and exit 56 | singleRun = false; 57 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var yeoman = require('yeoman-generator'); 5 | 6 | 7 | var MeanstackGenerator = module.exports = function MeanstackGenerator(args, options, config) { 8 | yeoman.generators.Base.apply(this, arguments); 9 | 10 | this.on('end', function () { 11 | this.installDependencies({ 12 | skipInstall: options['skip-install'] 13 | }); 14 | }); 15 | 16 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 17 | }; 18 | 19 | util.inherits(MeanstackGenerator, yeoman.generators.Base); 20 | 21 | MeanstackGenerator.prototype.askFor = function askFor() { 22 | var cb = this.async(); 23 | 24 | // have Yeoman greet the user. 25 | console.log(this.yeoman); 26 | 27 | var prompts = [ 28 | { 29 | type: 'confirm', 30 | name: 'herokuIntegration', 31 | message: 'Are you planning to deploy this project on Heroku?', 32 | default: false 33 | }, 34 | { 35 | type: 'confirm', 36 | name: 'angularStable', 37 | message: 'Prefer stable version of AngularJS?', 38 | default: true 39 | } 40 | ]; 41 | 42 | this.prompt(prompts, function (props) { 43 | this.herokuIntegration = props.herokuIntegration; 44 | this.angularStable = props.angularStable; 45 | 46 | cb(); 47 | }.bind(this)); 48 | }; 49 | 50 | MeanstackGenerator.prototype.app = function app() { 51 | this.mkdir('public'); 52 | this.mkdir('public/images'); 53 | this.mkdir('public/javascripts'); 54 | this.mkdir('public/stylesheets'); 55 | this.mkdir('config'); 56 | this.mkdir('config/environments'); 57 | this.mkdir('routes'); 58 | this.mkdir('views'); 59 | 60 | this.directory('public'); 61 | this.directory('routes'); 62 | this.directory('views'); 63 | this.directory('config'); 64 | 65 | // Frontend 66 | this.mkdir('app'); 67 | this.mkdir('app/scripts'); 68 | this.mkdir('app/styles'); 69 | this.mkdir('app/views'); 70 | this.directory('app'); 71 | this.mkdir('test'); 72 | this.mkdir('test/spec'); 73 | this.mkdir('test/spec/controllers'); 74 | this.directory('test'); 75 | }; 76 | 77 | MeanstackGenerator.prototype.projectfiles = function projectfiles() { 78 | // Dotfiles 79 | this.copy('_bowerrc', '.bowerrc'); 80 | this.copy('_editorconfig', '.editorconfig'); 81 | this.copy('_jshintrc', '.jshintrc'); 82 | this.copy('_gitattributes', '.gitattributes'); 83 | 84 | // Package 85 | this.copy('_package.json', 'package.json'); 86 | 87 | // Front 88 | this.copy('_bower.json', 'bower.json'); 89 | this.copy('_Gruntfile.js', 'Gruntfile.js'); 90 | this.copy('_karma-e2e.conf.js', 'karma-e2e.conf.js'); 91 | this.copy('_karma.conf.js', 'karma.conf.js'); 92 | 93 | // Express 94 | this.copy('_app.js', 'app.js'); 95 | this.copy('_app_grunt.js', 'app_grunt.js'); 96 | this.copy('_server.js', 'server.js'); 97 | 98 | if (this.herokuIntegration) { 99 | this.copy('_Procfile', 'Procfile'); 100 | this.copy('_env', '.env'); 101 | } 102 | }; 103 | -------------------------------------------------------------------------------- /app/templates/app/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

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

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /app/templates/_Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on 2013-07-11 using generator-angular 0.3.0 2 | 'use strict'; 3 | var LIVERELOAD_PORT = 35729; 4 | var path = require('path'); 5 | 6 | // # Globbing 7 | // for performance reasons we're only matching one level down: 8 | // 'test/spec/{,*/}*.js' 9 | // use this if you want to recursively match all subfolders: 10 | // 'test/spec/**/*.js' 11 | 12 | module.exports = function (grunt) { 13 | // load all grunt tasks 14 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); 15 | // show elapsed time at the end 16 | require('time-grunt')(grunt); 17 | 18 | // configurable paths 19 | var yeomanConfig = { 20 | app: 'app', 21 | dist: 'dist' 22 | }; 23 | 24 | try { 25 | yeomanConfig.app = require('./bower.json').appPath || yeomanConfig.app; 26 | } catch (e) {} 27 | 28 | grunt.loadNpmTasks('grunt-express'); 29 | 30 | grunt.initConfig({ 31 | yeoman: yeomanConfig, 32 | watch: { 33 | coffee: { 34 | files: ['<%= yeoman.app %>/scripts/{,*/}*.coffee'], 35 | tasks: ['coffee:dist'] 36 | }, 37 | coffeeTest: { 38 | files: ['test/spec/{,*/}*.coffee'], 39 | tasks: ['coffee:test'] 40 | }, 41 | livereload: { 42 | options: { 43 | livereload: LIVERELOAD_PORT 44 | }, 45 | files: [ 46 | '<%= yeoman.app %>/{,*/}*.html', 47 | '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css', 48 | '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', 49 | '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' 50 | ] 51 | } 52 | }, 53 | express: { 54 | options: { 55 | port: 3000, 56 | hostname: '*' 57 | }, 58 | livereload: { 59 | options: { 60 | livereload: true, 61 | server: path.resolve('app.js'), 62 | bases: [path.resolve('./.tmp'), path.resolve(__dirname, yeomanConfig.app)] 63 | } 64 | }, 65 | test: { 66 | options: { 67 | server: path.resolve('app.js'), 68 | bases: [path.resolve('./.tmp'), path.resolve(__dirname, 'test')] 69 | } 70 | }, 71 | dist: { 72 | options: { 73 | server: path.resolve('app.js'), 74 | bases: path.resolve(__dirname, yeomanConfig.dist) 75 | } 76 | } 77 | }, 78 | open: { 79 | server: { 80 | url: 'http://localhost:<%= express.options.port %>' 81 | } 82 | }, 83 | clean: { 84 | dist: { 85 | files: [{ 86 | dot: true, 87 | src: [ 88 | '.tmp', 89 | '<%= yeoman.dist %>/*', 90 | '!<%= yeoman.dist %>/.git*' 91 | ] 92 | }] 93 | }, 94 | server: '.tmp' 95 | }, 96 | jshint: { 97 | options: { 98 | jshintrc: '.jshintrc' 99 | }, 100 | all: [ 101 | 'Gruntfile.js', 102 | '<%= yeoman.app %>/scripts/{,*/}*.js' 103 | ] 104 | }, 105 | coffee: { 106 | dist: { 107 | files: [{ 108 | expand: true, 109 | cwd: '<%= yeoman.app %>/scripts', 110 | src: '{,*/}*.coffee', 111 | dest: '.tmp/scripts', 112 | ext: '.js' 113 | }] 114 | }, 115 | test: { 116 | files: [{ 117 | expand: true, 118 | cwd: 'test/spec', 119 | src: '{,*/}*.coffee', 120 | dest: '.tmp/spec', 121 | ext: '.js' 122 | }] 123 | } 124 | }, 125 | // not used since Uglify task does concat, 126 | // but still available if needed 127 | /*concat: { 128 | dist: {} 129 | },*/ 130 | rev: { 131 | dist: { 132 | files: { 133 | src: [ 134 | '<%= yeoman.dist %>/scripts/{,*/}*.js', 135 | '<%= yeoman.dist %>/styles/{,*/}*.css', 136 | '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}', 137 | '<%= yeoman.dist %>/styles/fonts/*' 138 | ] 139 | } 140 | } 141 | }, 142 | useminPrepare: { 143 | html: '<%= yeoman.app %>/index.html', 144 | options: { 145 | dest: '<%= yeoman.dist %>' 146 | } 147 | }, 148 | usemin: { 149 | html: ['<%= yeoman.dist %>/{,*/}*.html'], 150 | css: ['<%= yeoman.dist %>/styles/{,*/}*.css'], 151 | options: { 152 | dirs: ['<%= yeoman.dist %>'] 153 | } 154 | }, 155 | imagemin: { 156 | dist: { 157 | files: [{ 158 | expand: true, 159 | cwd: '<%= yeoman.app %>/images', 160 | src: '{,*/}*.{png,jpg,jpeg}', 161 | dest: '<%= yeoman.dist %>/images' 162 | }] 163 | } 164 | }, 165 | cssmin: { 166 | // By default, your `index.html` will take care of 167 | // minification. This option is pre-configured if you do not wish to use 168 | // Usemin blocks. 169 | // dist: { 170 | // files: { 171 | // '<%= yeoman.dist %>/styles/main.css': [ 172 | // '.tmp/styles/{,*/}*.css', 173 | // '<%= yeoman.app %>/styles/{,*/}*.css' 174 | // ] 175 | // } 176 | // } 177 | }, 178 | htmlmin: { 179 | dist: { 180 | options: { 181 | /*removeCommentsFromCDATA: true, 182 | // https://github.com/yeoman/grunt-usemin/issues/44 183 | //collapseWhitespace: true, 184 | collapseBooleanAttributes: true, 185 | removeAttributeQuotes: true, 186 | removeRedundantAttributes: true, 187 | useShortDoctype: true, 188 | removeEmptyAttributes: true, 189 | removeOptionalTags: true*/ 190 | }, 191 | files: [{ 192 | expand: true, 193 | cwd: '<%= yeoman.app %>', 194 | src: ['*.html', 'views/*.html'], 195 | dest: '<%= yeoman.dist %>' 196 | }] 197 | } 198 | }, 199 | // Put files not handled in other tasks here 200 | copy: { 201 | dist: { 202 | files: [{ 203 | expand: true, 204 | dot: true, 205 | cwd: '<%= yeoman.app %>', 206 | dest: '<%= yeoman.dist %>', 207 | src: [ 208 | '*.{ico,png,txt}', 209 | '.htaccess', 210 | 'bower_components/**/*', 211 | 'images/{,*/}*.{gif,webp,svg}', 212 | 'styles/fonts/*' 213 | ] 214 | }, { 215 | expand: true, 216 | cwd: '.tmp/images', 217 | dest: '<%= yeoman.dist %>/images', 218 | src: [ 219 | 'generated/*' 220 | ] 221 | }] 222 | } 223 | }, 224 | concurrent: { 225 | server: [ 226 | 'coffee:dist' 227 | ], 228 | test: [ 229 | 'coffee' 230 | ], 231 | dist: [ 232 | 'coffee', 233 | 'imagemin', 234 | 'htmlmin' 235 | ] 236 | }, 237 | karma: { 238 | unit: { 239 | configFile: 'karma.conf.js', 240 | singleRun: true 241 | } 242 | }, 243 | cdnify: { 244 | dist: { 245 | html: ['<%= yeoman.dist %>/*.html'] 246 | } 247 | }, 248 | ngmin: { 249 | dist: { 250 | files: [{ 251 | expand: true, 252 | cwd: '<%= yeoman.dist %>/scripts', 253 | src: '*.js', 254 | dest: '<%= yeoman.dist %>/scripts' 255 | }] 256 | } 257 | }, 258 | uglify: { 259 | dist: { 260 | files: { 261 | '<%= yeoman.dist %>/scripts/scripts.js': [ 262 | '<%= yeoman.dist %>/scripts/scripts.js' 263 | ] 264 | } 265 | } 266 | } 267 | }); 268 | 269 | grunt.registerTask('server', function (target) { 270 | if (target === 'dist') { 271 | return grunt.task.run(['build', 'open', 'express:dist', 'express-keepalive']); 272 | } 273 | 274 | grunt.task.run([ 275 | 'clean:server', 276 | 'concurrent:server', 277 | 'express:livereload', 278 | 'open', 279 | 'watch' 280 | ]); 281 | }); 282 | 283 | grunt.registerTask('test', [ 284 | 'clean:server', 285 | 'concurrent:test', 286 | 'express:test', 287 | 'karma' 288 | ]); 289 | 290 | grunt.registerTask('build', [ 291 | 'clean:dist', 292 | 'useminPrepare', 293 | 'concurrent:dist', 294 | 'concat', 295 | 'copy', 296 | 'cdnify', 297 | 'ngmin', 298 | 'cssmin', 299 | 'uglify', 300 | 'rev', 301 | 'usemin' 302 | ]); 303 | 304 | grunt.registerTask('default', [ 305 | 'jshint', 306 | 'test', 307 | 'build' 308 | ]); 309 | }; 310 | -------------------------------------------------------------------------------- /app/templates/app/.htaccess: -------------------------------------------------------------------------------- 1 | # Apache Configuration File 2 | 3 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have access 4 | # to the main server config file (usually called `httpd.conf`), you should add 5 | # this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. 6 | 7 | # ############################################################################## 8 | # # CROSS-ORIGIN RESOURCE SHARING (CORS) # 9 | # ############################################################################## 10 | 11 | # ------------------------------------------------------------------------------ 12 | # | Cross-domain AJAX requests | 13 | # ------------------------------------------------------------------------------ 14 | 15 | # Enable cross-origin AJAX requests. 16 | # http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity 17 | # http://enable-cors.org/ 18 | 19 | # 20 | # Header set Access-Control-Allow-Origin "*" 21 | # 22 | 23 | # ------------------------------------------------------------------------------ 24 | # | CORS-enabled images | 25 | # ------------------------------------------------------------------------------ 26 | 27 | # Send the CORS header for images when browsers request it. 28 | # https://developer.mozilla.org/en/CORS_Enabled_Image 29 | # http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html 30 | # http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ 31 | 32 | 33 | 34 | 35 | SetEnvIf Origin ":" IS_CORS 36 | Header set Access-Control-Allow-Origin "*" env=IS_CORS 37 | 38 | 39 | 40 | 41 | # ------------------------------------------------------------------------------ 42 | # | Web fonts access | 43 | # ------------------------------------------------------------------------------ 44 | 45 | # Allow access from all domains for web fonts 46 | 47 | 48 | 49 | Header set Access-Control-Allow-Origin "*" 50 | 51 | 52 | 53 | 54 | # ############################################################################## 55 | # # ERRORS # 56 | # ############################################################################## 57 | 58 | # ------------------------------------------------------------------------------ 59 | # | 404 error prevention for non-existing redirected folders | 60 | # ------------------------------------------------------------------------------ 61 | 62 | # Prevent Apache from returning a 404 error for a rewrite if a directory 63 | # with the same name does not exist. 64 | # http://httpd.apache.org/docs/current/content-negotiation.html#multiviews 65 | # http://www.webmasterworld.com/apache/3808792.htm 66 | 67 | Options -MultiViews 68 | 69 | # ------------------------------------------------------------------------------ 70 | # | Custom error messages / pages | 71 | # ------------------------------------------------------------------------------ 72 | 73 | # You can customize what Apache returns to the client in case of an error (see 74 | # http://httpd.apache.org/docs/current/mod/core.html#errordocument), e.g.: 75 | 76 | ErrorDocument 404 /404.html 77 | 78 | 79 | # ############################################################################## 80 | # # INTERNET EXPLORER # 81 | # ############################################################################## 82 | 83 | # ------------------------------------------------------------------------------ 84 | # | Better website experience | 85 | # ------------------------------------------------------------------------------ 86 | 87 | # Force IE to render pages in the highest available mode in the various 88 | # cases when it may not: http://hsivonen.iki.fi/doctype/ie-mode.pdf. 89 | # Use, if installed, Google Chrome Frame. 90 | 91 | 92 | Header set X-UA-Compatible "IE=edge,chrome=1" 93 | # `mod_headers` can't match based on the content-type, however, we only 94 | # want to send this header for HTML pages and not for the other resources 95 | 96 | Header unset X-UA-Compatible 97 | 98 | 99 | 100 | # ------------------------------------------------------------------------------ 101 | # | Cookie setting from iframes | 102 | # ------------------------------------------------------------------------------ 103 | 104 | # Allow cookies to be set from iframes in IE. 105 | 106 | # 107 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 108 | # 109 | 110 | # ------------------------------------------------------------------------------ 111 | # | Screen flicker | 112 | # ------------------------------------------------------------------------------ 113 | 114 | # Stop screen flicker in IE on CSS rollovers (this only works in 115 | # combination with the `ExpiresByType` directives for images from below). 116 | 117 | # BrowserMatch "MSIE" brokenvary=1 118 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 119 | # BrowserMatch "Opera" !brokenvary 120 | # SetEnvIf brokenvary 1 force-no-vary 121 | 122 | 123 | # ############################################################################## 124 | # # MIME TYPES AND ENCODING # 125 | # ############################################################################## 126 | 127 | # ------------------------------------------------------------------------------ 128 | # | Proper MIME types for all files | 129 | # ------------------------------------------------------------------------------ 130 | 131 | 132 | 133 | # Audio 134 | AddType audio/mp4 m4a f4a f4b 135 | AddType audio/ogg oga ogg 136 | 137 | # JavaScript 138 | # Normalize to standard type (it's sniffed in IE anyways): 139 | # http://tools.ietf.org/html/rfc4329#section-7.2 140 | AddType application/javascript js jsonp 141 | AddType application/json json 142 | 143 | # Video 144 | AddType video/mp4 mp4 m4v f4v f4p 145 | AddType video/ogg ogv 146 | AddType video/webm webm 147 | AddType video/x-flv flv 148 | 149 | # Web fonts 150 | AddType application/font-woff woff 151 | AddType application/vnd.ms-fontobject eot 152 | 153 | # Browsers usually ignore the font MIME types and sniff the content, 154 | # however, Chrome shows a warning if other MIME types are used for the 155 | # following fonts. 156 | AddType application/x-font-ttf ttc ttf 157 | AddType font/opentype otf 158 | 159 | # Make SVGZ fonts work on iPad: 160 | # https://twitter.com/FontSquirrel/status/14855840545 161 | AddType image/svg+xml svg svgz 162 | AddEncoding gzip svgz 163 | 164 | # Other 165 | AddType application/octet-stream safariextz 166 | AddType application/x-chrome-extension crx 167 | AddType application/x-opera-extension oex 168 | AddType application/x-shockwave-flash swf 169 | AddType application/x-web-app-manifest+json webapp 170 | AddType application/x-xpinstall xpi 171 | AddType application/xml atom rdf rss xml 172 | AddType image/webp webp 173 | AddType image/x-icon ico 174 | AddType text/cache-manifest appcache manifest 175 | AddType text/vtt vtt 176 | AddType text/x-component htc 177 | AddType text/x-vcard vcf 178 | 179 | 180 | 181 | # ------------------------------------------------------------------------------ 182 | # | UTF-8 encoding | 183 | # ------------------------------------------------------------------------------ 184 | 185 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 186 | AddDefaultCharset utf-8 187 | 188 | # Force UTF-8 for certain file formats. 189 | 190 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml 191 | 192 | 193 | 194 | # ############################################################################## 195 | # # URL REWRITES # 196 | # ############################################################################## 197 | 198 | # ------------------------------------------------------------------------------ 199 | # | Rewrite engine | 200 | # ------------------------------------------------------------------------------ 201 | 202 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is 203 | # necessary for the following directives to work. 204 | 205 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 206 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the 207 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 208 | 209 | # Also, some cloud hosting services require `RewriteBase` to be set: 210 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 211 | 212 | 213 | Options +FollowSymlinks 214 | # Options +SymLinksIfOwnerMatch 215 | RewriteEngine On 216 | # RewriteBase / 217 | 218 | 219 | # ------------------------------------------------------------------------------ 220 | # | Suppressing / Forcing the "www." at the beginning of URLs | 221 | # ------------------------------------------------------------------------------ 222 | 223 | # The same content should never be available under two different URLs especially 224 | # not with and without "www." at the beginning. This can cause SEO problems 225 | # (duplicate content), therefore, you should choose one of the alternatives and 226 | # redirect the other one. 227 | 228 | # By default option 1 (no "www.") is activated: 229 | # http://no-www.org/faq.php?q=class_b 230 | 231 | # If you'd prefer to use option 2, just comment out all the lines from option 1 232 | # and uncomment the ones from option 2. 233 | 234 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 235 | 236 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 237 | 238 | # Option 1: rewrite www.example.com → example.com 239 | 240 | 241 | RewriteCond %{HTTPS} !=on 242 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 243 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 244 | 245 | 246 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 247 | 248 | # Option 2: rewrite example.com → www.example.com 249 | 250 | # Be aware that the following might not be a good idea if you use "real" 251 | # subdomains for certain parts of your website. 252 | 253 | # 254 | # RewriteCond %{HTTPS} !=on 255 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] 256 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 257 | # 258 | 259 | 260 | # ############################################################################## 261 | # # SECURITY # 262 | # ############################################################################## 263 | 264 | # ------------------------------------------------------------------------------ 265 | # | Content Security Policy (CSP) | 266 | # ------------------------------------------------------------------------------ 267 | 268 | # You can mitigate the risk of cross-site scripting and other content-injection 269 | # attacks by setting a Content Security Policy which whitelists trusted sources 270 | # of content for your site. 271 | 272 | # The example header below allows ONLY scripts that are loaded from the current 273 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 274 | # work as-is for your site! 275 | 276 | # To get all the details you'll need to craft a reasonable policy for your site, 277 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or 278 | # see the specification: http://w3.org/TR/CSP). 279 | 280 | # 281 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 282 | # 283 | # Header unset Content-Security-Policy 284 | # 285 | # 286 | 287 | # ------------------------------------------------------------------------------ 288 | # | File access | 289 | # ------------------------------------------------------------------------------ 290 | 291 | # Block access to directories without a default document. 292 | # Usually you should leave this uncommented because you shouldn't allow anyone 293 | # to surf through every directory on your server (which may includes rather 294 | # private places like the CMS's directories). 295 | 296 | 297 | Options -Indexes 298 | 299 | 300 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 301 | 302 | # Block access to hidden files and directories. 303 | # This includes directories used by version control systems such as Git and SVN. 304 | 305 | 306 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 307 | RewriteCond %{SCRIPT_FILENAME} -f 308 | RewriteRule "(^|/)\." - [F] 309 | 310 | 311 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 312 | 313 | # Block access to backup and source files. 314 | # These files may be left by some text editors and can pose a great security 315 | # danger when anyone has access to them. 316 | 317 | 318 | Order allow,deny 319 | Deny from all 320 | Satisfy All 321 | 322 | 323 | # ------------------------------------------------------------------------------ 324 | # | Secure Sockets Layer (SSL) | 325 | # ------------------------------------------------------------------------------ 326 | 327 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: 328 | # prevent `https://www.example.com` when your certificate only allows 329 | # `https://secure.example.com`. 330 | 331 | # 332 | # RewriteCond %{SERVER_PORT} !^443 333 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 334 | # 335 | 336 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 337 | 338 | # Force client-side SSL redirection. 339 | 340 | # If a user types "example.com" in his browser, the above rule will redirect him 341 | # to the secure version of the site. That still leaves a window of opportunity 342 | # (the initial HTTP connection) for an attacker to downgrade or redirect the 343 | # request. The following header ensures that browser will ONLY connect to your 344 | # server via HTTPS, regardless of what the users type in the address bar. 345 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 346 | 347 | # 348 | # Header set Strict-Transport-Security max-age=16070400; 349 | # 350 | 351 | # ------------------------------------------------------------------------------ 352 | # | Server software information | 353 | # ------------------------------------------------------------------------------ 354 | 355 | # Avoid displaying the exact Apache version number, the description of the 356 | # generic OS-type and the information about Apache's compiled-in modules. 357 | 358 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 359 | 360 | # ServerTokens Prod 361 | 362 | 363 | # ############################################################################## 364 | # # WEB PERFORMANCE # 365 | # ############################################################################## 366 | 367 | # ------------------------------------------------------------------------------ 368 | # | Compression | 369 | # ------------------------------------------------------------------------------ 370 | 371 | 372 | 373 | # Force compression for mangled headers. 374 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 375 | 376 | 377 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 378 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 379 | 380 | 381 | 382 | # Compress all output labeled with one of the following MIME-types 383 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 384 | # and can remove the `` and `` lines 385 | # as `AddOutputFilterByType` is still in the core directives). 386 | 387 | AddOutputFilterByType DEFLATE application/atom+xml \ 388 | application/javascript \ 389 | application/json \ 390 | application/rss+xml \ 391 | application/vnd.ms-fontobject \ 392 | application/x-font-ttf \ 393 | application/x-web-app-manifest+json \ 394 | application/xhtml+xml \ 395 | application/xml \ 396 | font/opentype \ 397 | image/svg+xml \ 398 | image/x-icon \ 399 | text/css \ 400 | text/html \ 401 | text/plain \ 402 | text/x-component \ 403 | text/xml 404 | 405 | 406 | 407 | 408 | # ------------------------------------------------------------------------------ 409 | # | Content transformations | 410 | # ------------------------------------------------------------------------------ 411 | 412 | # Prevent some of the mobile network providers from modifying the content of 413 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 414 | 415 | # 416 | # Header set Cache-Control "no-transform" 417 | # 418 | 419 | # ------------------------------------------------------------------------------ 420 | # | ETag removal | 421 | # ------------------------------------------------------------------------------ 422 | 423 | # Since we're sending far-future expires headers (see below), ETags can 424 | # be removed: http://developer.yahoo.com/performance/rules.html#etags. 425 | 426 | # `FileETag None` is not enough for every server. 427 | 428 | Header unset ETag 429 | 430 | 431 | FileETag None 432 | 433 | # ------------------------------------------------------------------------------ 434 | # | Expires headers (for better cache control) | 435 | # ------------------------------------------------------------------------------ 436 | 437 | # The following expires headers are set pretty far in the future. If you don't 438 | # control versioning with filename-based cache busting, consider lowering the 439 | # cache time for resources like CSS and JS to something like 1 week. 440 | 441 | 442 | 443 | ExpiresActive on 444 | ExpiresDefault "access plus 1 month" 445 | 446 | # CSS 447 | ExpiresByType text/css "access plus 1 year" 448 | 449 | # Data interchange 450 | ExpiresByType application/json "access plus 0 seconds" 451 | ExpiresByType application/xml "access plus 0 seconds" 452 | ExpiresByType text/xml "access plus 0 seconds" 453 | 454 | # Favicon (cannot be renamed!) 455 | ExpiresByType image/x-icon "access plus 1 week" 456 | 457 | # HTML components (HTCs) 458 | ExpiresByType text/x-component "access plus 1 month" 459 | 460 | # HTML 461 | ExpiresByType text/html "access plus 0 seconds" 462 | 463 | # JavaScript 464 | ExpiresByType application/javascript "access plus 1 year" 465 | 466 | # Manifest files 467 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 468 | ExpiresByType text/cache-manifest "access plus 0 seconds" 469 | 470 | # Media 471 | ExpiresByType audio/ogg "access plus 1 month" 472 | ExpiresByType image/gif "access plus 1 month" 473 | ExpiresByType image/jpeg "access plus 1 month" 474 | ExpiresByType image/png "access plus 1 month" 475 | ExpiresByType video/mp4 "access plus 1 month" 476 | ExpiresByType video/ogg "access plus 1 month" 477 | ExpiresByType video/webm "access plus 1 month" 478 | 479 | # Web feeds 480 | ExpiresByType application/atom+xml "access plus 1 hour" 481 | ExpiresByType application/rss+xml "access plus 1 hour" 482 | 483 | # Web fonts 484 | ExpiresByType application/font-woff "access plus 1 month" 485 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 486 | ExpiresByType application/x-font-ttf "access plus 1 month" 487 | ExpiresByType font/opentype "access plus 1 month" 488 | ExpiresByType image/svg+xml "access plus 1 month" 489 | 490 | 491 | 492 | # ------------------------------------------------------------------------------ 493 | # | Filename-based cache busting | 494 | # ------------------------------------------------------------------------------ 495 | 496 | # If you're not using a build process to manage your filename version revving, 497 | # you might want to consider enabling the following directives to route all 498 | # requests such as `/css/style.12345.css` to `/css/style.css`. 499 | 500 | # To understand why this is important and a better idea than `*.css?v231`, read: 501 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 502 | 503 | # 504 | # RewriteCond %{REQUEST_FILENAME} !-f 505 | # RewriteCond %{REQUEST_FILENAME} !-d 506 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] 507 | # 508 | 509 | # ------------------------------------------------------------------------------ 510 | # | File concatenation | 511 | # ------------------------------------------------------------------------------ 512 | 513 | # Allow concatenation from within specific CSS and JS files, e.g.: 514 | # Inside of `script.combined.js` you could have 515 | # 516 | # 517 | # and they would be included into this single file. 518 | 519 | # 520 | # 521 | # Options +Includes 522 | # AddOutputFilterByType INCLUDES application/javascript application/json 523 | # SetOutputFilter INCLUDES 524 | # 525 | # 526 | # Options +Includes 527 | # AddOutputFilterByType INCLUDES text/css 528 | # SetOutputFilter INCLUDES 529 | # 530 | # 531 | 532 | # ------------------------------------------------------------------------------ 533 | # | Persistent connections | 534 | # ------------------------------------------------------------------------------ 535 | 536 | # Allow multiple requests to be sent over the same TCP connection: 537 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. 538 | 539 | # Enable if you serve a lot of static content but, be aware of the 540 | # possible disadvantages! 541 | 542 | # 543 | # Header set Connection Keep-Alive 544 | # 545 | --------------------------------------------------------------------------------