├── .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 | [](https://travis-ci.org/wlepinski/generator-meanstack)
3 | [](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 |
148 | - a mistyped address
149 | - an out-of-date link
150 |
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 |
--------------------------------------------------------------------------------