├── .editorconfig ├── .gitattributes ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── README.md ├── app ├── USAGE ├── index.js └── templates │ ├── 404.html │ ├── Gruntfile.js │ ├── _bower.json │ ├── _package.json │ ├── app-require.jsx │ ├── app.jsx │ ├── bowerrc │ ├── editorconfig │ ├── favicon.ico │ ├── gitattributes │ ├── gitignore │ ├── htaccess │ ├── index.html │ ├── jshintrc │ ├── main-require.jsx │ ├── main.css │ └── robots.txt ├── changelog.md ├── contributing.md ├── package.json └── test └── test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | temp/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "esnext": true, 4 | "bitwise": false, 5 | "curly": false, 6 | "eqeqeq": true, 7 | "eqnull": true, 8 | "immed": true, 9 | "latedef": true, 10 | "newcap": true, 11 | "noarg": true, 12 | "undef": true, 13 | "strict": false, 14 | "trailing": true, 15 | "smarttabs": true 16 | } 17 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | .editorconfig 3 | .travis.yml 4 | .jshintrc 5 | .gitattributes 6 | contributing.md 7 | test 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | - '0.8' 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React App generator 2 | 3 | Yeoman generator that scaffolds out a React web app. 4 | 5 | ## Features 6 | 7 | * CSS Autoprefixing (new) 8 | * Built-in preview server with LiveReload 9 | * Automagically lint your scripts 10 | * Automagically wire up your Bower components with [bower-install](https://github.com/stephenplusplus/grunt-bower-install). 11 | * Awesome Image Optimization (via OptiPNG, pngquant, jpegtran and gifsicle) 12 | * Mocha Unit Testing with PhantomJS 13 | * Optional - Leaner Modernizr builds 14 | * Optional - RequireJS AMD support 15 | 16 | For more information on what `generator-react` can do for you, take a look at the [Grunt tasks](https://github.com/nemophrost/generator-react/blob/master/app/templates/_package.json) used in `package.json`. 17 | 18 | ## Getting Started 19 | 20 | - Install: `npm install -g generator-react` 21 | - Run: `yo react` 22 | - Run `grunt` for building and `grunt serve` for preview 23 | 24 | 25 | ## Options 26 | 27 | * `--skip-install` 28 | 29 | Skips the automatic execution of `bower` and `npm` after scaffolding has finished. 30 | 31 | * `--test-framework=` 32 | 33 | Defaults to `mocha`. Can be switched for another supported testing framework like `jasmine`. 34 | 35 | ## Contribute 36 | 37 | Submit a pull request and I'll see what I can do. Thanks! 38 | 39 | ## License 40 | 41 | [BSD license](http://opensource.org/licenses/bsd-license.php) 42 | -------------------------------------------------------------------------------- /app/USAGE: -------------------------------------------------------------------------------- 1 | Description: 2 | Creates a new basic front-end web application. 3 | 4 | Options: 5 | Twitter Bootstrap: Include Twitter Bootstrap for Sass 6 | 7 | Example: 8 | yo webapp [--coffee] 9 | 10 | This will create: 11 | Gruntfile.js: Configuration for the task runner. 12 | bower.json: Front-end packages installed by bower. 13 | package.json: Development packages installed by npm. 14 | 15 | app/: Your application files. 16 | test/: Unit tests for your application. 17 | -------------------------------------------------------------------------------- /app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var util = require('util'); 3 | var path = require('path'); 4 | var spawn = require('child_process').spawn; 5 | var yeoman = require('yeoman-generator'); 6 | 7 | 8 | var ReactGenerator = module.exports = function ReactGenerator(args, options, config) { 9 | yeoman.generators.Base.apply(this, arguments); 10 | 11 | // setup the test-framework property, Gruntfile template will need this 12 | this.testFramework = options['test-framework'] || 'mocha'; 13 | 14 | // for hooks to resolve on mocha by default 15 | options['test-framework'] = this.testFramework; 16 | 17 | // resolved to mocha by default (could be switched to jasmine for instance) 18 | this.hookFor('test-framework', { as: 'app' }); 19 | 20 | this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json'))); 21 | }; 22 | 23 | util.inherits(ReactGenerator, yeoman.generators.Base); 24 | 25 | ReactGenerator.prototype.askFor = function askFor() { 26 | var cb = this.async(); 27 | 28 | // welcome message 29 | if (!this.options['skip-welcome-message']) { 30 | console.log(this.yeoman); 31 | console.log('Out of the box I include HTML5 Boilerplate and jQuery.'); 32 | } 33 | 34 | var prompts = [ 35 | { 36 | type: 'checkbox', 37 | name: 'features', 38 | message: 'What more would you like?', 39 | choices: [{ 40 | name: 'React Addons', 41 | value: 'reactAddons', 42 | checked: true 43 | },{ 44 | name: 'RequireJS Support', 45 | value: 'requireJS', 46 | checked: true 47 | },{ 48 | name: 'Modernizr', 49 | value: 'includeModernizr', 50 | checked: true 51 | }] 52 | }/*,{ 53 | type: 'list', 54 | name: 'cssPreprocessor', 55 | message: 'Would you like to include a CSS pre-processor?', 56 | choices: [{ 57 | name: 'No', 58 | value: 'none' 59 | },{ 60 | name: 'SCSS', 61 | value: 'scss' 62 | },{ 63 | name: 'LESS', 64 | value: 'less' 65 | },{ 66 | name: 'Stylus', 67 | value: 'stylus' 68 | }] 69 | }*/ 70 | ]; 71 | 72 | this.prompt(prompts, function (answers) { 73 | var features = answers.features; 74 | 75 | function hasFeature(feat) { return features.indexOf(feat) !== -1; } 76 | 77 | // manually deal with the response, get back and store the results. 78 | // we change a bit this way of doing to automatically do this in the self.prompt() method. 79 | this.reactAddons = hasFeature('reactAddons'); 80 | this.requireJS = hasFeature('requireJS'); 81 | this.includeModernizr = hasFeature('includeModernizr'); 82 | // this.cssPreprocessor = answers.cssPreprocessor; 83 | 84 | cb(); 85 | }.bind(this)); 86 | }; 87 | 88 | ReactGenerator.prototype.gruntfile = function gruntfile() { 89 | this.template('Gruntfile.js'); 90 | }; 91 | 92 | ReactGenerator.prototype.packageJSON = function packageJSON() { 93 | this.template('_package.json', 'package.json'); 94 | }; 95 | 96 | ReactGenerator.prototype.git = function git() { 97 | this.copy('gitignore', '.gitignore'); 98 | this.copy('gitattributes', '.gitattributes'); 99 | }; 100 | 101 | ReactGenerator.prototype.bower = function bower() { 102 | this.copy('bowerrc', '.bowerrc'); 103 | this.copy('_bower.json', 'bower.json'); 104 | }; 105 | 106 | ReactGenerator.prototype.jshint = function jshint() { 107 | this.copy('jshintrc', '.jshintrc'); 108 | }; 109 | 110 | ReactGenerator.prototype.editorConfig = function editorConfig() { 111 | this.copy('editorconfig', '.editorconfig'); 112 | }; 113 | 114 | ReactGenerator.prototype.h5bp = function h5bp() { 115 | this.copy('favicon.ico', 'app/favicon.ico'); 116 | this.copy('404.html', 'app/404.html'); 117 | this.copy('robots.txt', 'app/robots.txt'); 118 | this.copy('htaccess', 'app/.htaccess'); 119 | }; 120 | 121 | ReactGenerator.prototype.mainStylesheet = function mainStylesheet() { 122 | // TODO: Add support for SCSS, LESS, and STYLUS 123 | this.copy('main.css', 'app/styles/main.css'); 124 | }; 125 | 126 | ReactGenerator.prototype.writeIndex = function writeIndex() { 127 | this.indexFile = this.readFileAsString(path.join(this.sourceRoot(), 'index.html')); 128 | this.indexFile = this.engine(this.indexFile, this); 129 | }; 130 | 131 | ReactGenerator.prototype.requirejs = function requirejs() { 132 | if (this.requireJS) { 133 | this.copy('app-require.jsx', 'app/jsx/app.jsx'); 134 | this.copy('main-require.jsx', 'app/jsx/main.jsx'); 135 | } else { 136 | this.copy('app.jsx', 'app/jsx/app.jsx'); 137 | } 138 | }; 139 | 140 | 141 | ReactGenerator.prototype.app = function app() { 142 | this.mkdir('app'); 143 | this.mkdir('app/jsx'); 144 | this.mkdir('app/scripts'); 145 | this.mkdir('app/styles'); 146 | this.mkdir('app/images'); 147 | this.write('app/index.html', this.indexFile); 148 | }; 149 | 150 | ReactGenerator.prototype.install = function() { 151 | this.invoke(this.options['test-framework'], { 152 | options: { 153 | 'skip-message': this.options['skip-install-message'], 154 | 'skip-install': this.options['skip-install'], 155 | 'coffee': this.options.coffee 156 | } 157 | }); 158 | 159 | if (!this.options['skip-install-message']) { 160 | this.bowerInstall(); 161 | this.npmInstall(); 162 | } 163 | }; 164 | -------------------------------------------------------------------------------- /app/templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Page Not Found :( 6 | 141 | 142 | 143 |
144 |

Not found :(

145 |

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

146 |

It looks like this was the result of either:

147 | 151 | 154 | 155 |
156 | 157 | 158 | -------------------------------------------------------------------------------- /app/templates/Gruntfile.js: -------------------------------------------------------------------------------- 1 | // Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %> 2 | 'use strict'; 3 | 4 | // # Globbing 5 | // for performance reasons we're only matching one level down: 6 | // 'test/spec/{,*/}*.js' 7 | // use this if you want to recursively match all subfolders: 8 | // 'test/spec/**/*.js' 9 | 10 | module.exports = function (grunt) { 11 | 12 | // Load grunt tasks automatically 13 | require('load-grunt-tasks')(grunt); 14 | 15 | // Time how long tasks take. Can help when optimizing build times 16 | require('time-grunt')(grunt); 17 | 18 | // Define the configuration for all the tasks 19 | grunt.initConfig({ 20 | 21 | // Project settings 22 | yeoman: { 23 | // Configurable paths 24 | app: 'app', 25 | dist: 'dist' 26 | }, 27 | 28 | // react 29 | react: { 30 | app: { 31 | options: { 32 | extension: 'jsx', // Default 33 | ignoreMTime: false // Default 34 | }, 35 | files: { 36 | '<%%= yeoman.app %>/scripts': '<%%= yeoman.app %>/jsx' 37 | } 38 | }, 39 | }, 40 | 41 | // Watches files for changes and runs tasks based on the changed files 42 | watch: { 43 | gruntfile: { 44 | files: ['Gruntfile.js'] 45 | }, 46 | react: { 47 | files: ['<%%= yeoman.app %>/jsx/{,*/}*.jsx'], 48 | tasks: ['react:app'] 49 | }, 50 | styles: { 51 | files: ['<%%= yeoman.app %>/styles/{,*/}*.css'], 52 | tasks: ['newer:copy:styles', 'autoprefixer'] 53 | }, 54 | livereload: { 55 | options: { 56 | livereload: '<%%= connect.options.livereload %>' 57 | }, 58 | files: [ 59 | '<%%= yeoman.app %>/*.html', 60 | '.tmp/styles/{,*/}*.css', 61 | '{.tmp,<%%= yeoman.app %>}/scripts/{,*/}*.js', 62 | '<%%= yeoman.app %>/images/{,*/}*.{gif,jpeg,jpg,png,svg,webp}' 63 | ] 64 | } 65 | }, 66 | 67 | // The actual grunt server settings 68 | connect: { 69 | options: { 70 | port: 9000, 71 | livereload: 35729, 72 | // Change this to '0.0.0.0' to access the server from outside 73 | hostname: 'localhost' 74 | }, 75 | livereload: { 76 | options: { 77 | open: true, 78 | base: [ 79 | '.tmp', 80 | '<%%= yeoman.app %>' 81 | ] 82 | } 83 | }, 84 | test: { 85 | options: { 86 | base: [ 87 | '.tmp', 88 | 'test', 89 | '<%%= yeoman.app %>' 90 | ] 91 | } 92 | }, 93 | dist: { 94 | options: { 95 | open: true, 96 | base: '<%%= yeoman.dist %>', 97 | livereload: false 98 | } 99 | } 100 | }, 101 | 102 | // Empties folders to start fresh 103 | clean: { 104 | dist: { 105 | files: [{ 106 | dot: true, 107 | src: [ 108 | '.tmp', 109 | '<%%= yeoman.dist %>/*', 110 | '!<%%= yeoman.dist %>/.git*' 111 | ] 112 | }] 113 | }, 114 | server: '.tmp' 115 | }, 116 | 117 | // Make sure code styles are up to par and there are no obvious mistakes 118 | jshint: { 119 | options: { 120 | jshintrc: '.jshintrc', 121 | reporter: require('jshint-stylish') 122 | }, 123 | all: [ 124 | 'Gruntfile.js', 125 | '<%%= yeoman.app %>/scripts/{,*/}*.js', 126 | '!<%%= yeoman.app %>/scripts/vendor/*', 127 | 'test/spec/{,*/}*.js' 128 | ] 129 | }, 130 | 131 | <% if (testFramework === 'mocha') { %> 132 | // Mocha testing framework configuration options 133 | mocha: { 134 | all: { 135 | options: { 136 | run: true, 137 | urls: ['http://<%%= connect.test.options.hostname %>:<%%= connect.test.options.port %>/index.html'] 138 | } 139 | } 140 | },<% } else if (testFramework === 'jasmine') { %> 141 | // Jasmine testing framework configuration options 142 | jasmine: { 143 | all: { 144 | options: { 145 | specs: 'test/spec/{,*/}*.js' 146 | } 147 | } 148 | },<% } %> 149 | 150 | <% if (requireJS) { %> 151 | requirejs: { 152 | compile: { 153 | options: { 154 | baseUrl: '<%%= yeoman.app %>/scripts', 155 | wrap: true, 156 | name: '../bower_components/almond/almond', 157 | preserveLicenseComments: false, 158 | optimize: 'uglify', // 'none', 159 | mainConfigFile: '<%%= yeoman.app %>/scripts/main.js', 160 | include: ['main'], 161 | out: '<%%= yeoman.dist %>/scripts/app.min.js' 162 | } 163 | } 164 | },<% } %> 165 | 166 | // Add vendor prefixed styles 167 | autoprefixer: { 168 | options: { 169 | browsers: ['last 1 version'] 170 | }, 171 | dist: { 172 | files: [{ 173 | expand: true, 174 | cwd: '.tmp/styles/', 175 | src: '{,*/}*.css', 176 | dest: '.tmp/styles/' 177 | }] 178 | } 179 | }, 180 | 181 | // Automatically inject Bower components into the HTML file 182 | 'bower-install': { 183 | app: { 184 | html: '<%%= yeoman.app %>/index.html', 185 | ignorePath: '<%%= yeoman.app %>/' 186 | } 187 | }, 188 | 189 | // Renames files for browser caching purposes 190 | rev: { 191 | dist: { 192 | files: { 193 | src: [ 194 | '<%%= yeoman.dist %>/scripts/{,*/}*.js', 195 | '<%%= yeoman.dist %>/styles/{,*/}*.css', 196 | '<%%= yeoman.dist %>/images/{,*/}*.{gif,jpeg,jpg,png,webp}', 197 | '<%%= yeoman.dist %>/styles/fonts/{,*/}*.*' 198 | ] 199 | } 200 | } 201 | }, 202 | 203 | // Reads HTML for usemin blocks to enable smart builds that automatically 204 | // concat, minify and revision files. Creates configurations in memory so 205 | // additional tasks can operate on them 206 | useminPrepare: { 207 | options: { 208 | dest: '<%%= yeoman.dist %>' 209 | }, 210 | html: '<%%= yeoman.app %>/index.html' 211 | }, 212 | 213 | // Performs rewrites based on rev and the useminPrepare configuration 214 | usemin: { 215 | options: { 216 | assetsDirs: ['<%%= yeoman.dist %>'] 217 | }, 218 | html: ['<%%= yeoman.dist %>/{,*/}*.html'], 219 | css: ['<%%= yeoman.dist %>/styles/{,*/}*.css'] 220 | }, 221 | 222 | // The following *-min tasks produce minified files in the dist folder 223 | imagemin: { 224 | dist: { 225 | files: [{ 226 | expand: true, 227 | cwd: '<%%= yeoman.app %>/images', 228 | src: '{,*/}*.{gif,jpeg,jpg,png}', 229 | dest: '<%%= yeoman.dist %>/images' 230 | }] 231 | } 232 | }, 233 | svgmin: { 234 | dist: { 235 | files: [{ 236 | expand: true, 237 | cwd: '<%%= yeoman.app %>/images', 238 | src: '{,*/}*.svg', 239 | dest: '<%%= yeoman.dist %>/images' 240 | }] 241 | } 242 | }, 243 | htmlmin: { 244 | dist: { 245 | options: { 246 | // removeCommentsFromCDATA: true, 247 | // collapseWhitespace: true, 248 | // collapseBooleanAttributes: true, 249 | // removeAttributeQuotes: true, 250 | // removeRedundantAttributes: true, 251 | // useShortDoctype: true, 252 | // removeEmptyAttributes: true, 253 | // removeOptionalTags: true 254 | }, 255 | files: [{ 256 | expand: true, 257 | cwd: '<%%= yeoman.app %>', 258 | src: '*.html', 259 | dest: '<%%= yeoman.dist %>' 260 | }] 261 | } 262 | }, 263 | 264 | // By default, your `index.html`'s will take care of 265 | // minification. These next options are pre-configured if you do not wish 266 | // to use the Usemin blocks. 267 | // cssmin: { 268 | // dist: { 269 | // files: { 270 | // '<%%= yeoman.dist %>/styles/main.css': [ 271 | // '.tmp/styles/{,*/}*.css', 272 | // '<%%= yeoman.app %>/styles/{,*/}*.css' 273 | // ] 274 | // } 275 | // } 276 | // }, 277 | // uglify: { 278 | // dist: { 279 | // files: { 280 | // '<%%= yeoman.dist %>/scripts/scripts.js': [ 281 | // '<%%= yeoman.dist %>/scripts/scripts.js' 282 | // ] 283 | // } 284 | // } 285 | // }, 286 | // concat: { 287 | // dist: {} 288 | // }, 289 | 290 | // Copies remaining files to places other tasks can use 291 | copy: { 292 | dist: { 293 | files: [{ 294 | expand: true, 295 | dot: true, 296 | cwd: '<%%= yeoman.app %>', 297 | dest: '<%%= yeoman.dist %>', 298 | src: [ 299 | '*.{ico,png,txt}', 300 | '.htaccess', 301 | 'images/{,*/}*.webp', 302 | 'styles/fonts/{,*/}*.*' 303 | ] 304 | }] 305 | }, 306 | styles: { 307 | expand: true, 308 | dot: true, 309 | cwd: '<%%= yeoman.app %>/styles', 310 | dest: '.tmp/styles/', 311 | src: '{,*/}*.css' 312 | } 313 | }, 314 | 315 | <% if (includeModernizr) { %> 316 | // Generates a custom Modernizr build that includes only the tests you 317 | // reference in your app 318 | modernizr: { 319 | devFile: '<%%= yeoman.app %>/bower_components/modernizr/modernizr.js', 320 | outputFile: '<%%= yeoman.dist %>/bower_components/modernizr/modernizr.js', 321 | files: [ 322 | '<%%= yeoman.dist %>/scripts/{,*/}*.js', 323 | '<%%= yeoman.dist %>/styles/{,*/}*.css', 324 | '!<%%= yeoman.dist %>/scripts/vendor/*' 325 | ], 326 | uglify: true 327 | },<% } %> 328 | 329 | // Run some tasks in parallel to speed up build process 330 | concurrent: { 331 | server: [ 332 | 'copy:styles' 333 | ], 334 | test: [ 335 | 'copy:styles' 336 | ], 337 | dist: [ 338 | 'copy:styles', 339 | 'react:app', 340 | 'imagemin', 341 | 'svgmin', 342 | 'htmlmin' 343 | ] 344 | }<% if (requireJS) { %>, 345 | bower: { 346 | options: { 347 | exclude: ['modernizr'] 348 | }, 349 | all: { 350 | rjsConfig: '<%%= yeoman.app %>/scripts/main.js' 351 | } 352 | }<% } %> 353 | }); 354 | 355 | 356 | grunt.registerTask('serve', function (target) { 357 | if (target === 'dist') { 358 | return grunt.task.run(['build', 'connect:dist:keepalive']); 359 | } 360 | 361 | grunt.task.run([ 362 | 'clean:server', 363 | 'react', 364 | 'concurrent:server', 365 | 'autoprefixer', 366 | 'connect:livereload', 367 | 'watch' 368 | ]); 369 | }); 370 | 371 | grunt.registerTask('test', [ 372 | 'clean:server', 373 | 'react', 374 | 'concurrent:test', 375 | 'autoprefixer', 376 | 'connect:test',<% if (testFramework === 'mocha') { %> 377 | 'mocha'<% } else if (testFramework === 'jasmine') { %> 378 | 'jasmine'<% } %> 379 | ]); 380 | 381 | grunt.registerTask('build', [ 382 | 'clean:dist', 383 | 'react', 384 | 'useminPrepare', 385 | 'concurrent:dist', 386 | 'autoprefixer', 387 | 'concat', 388 | 'cssmin', 389 | 'uglify',<% if (requireJS) { %> 390 | 'requirejs',<% } %><% if (includeModernizr) { %> 391 | 'modernizr',<% } %> 392 | 'copy:dist', 393 | 'rev', 394 | 'usemin' 395 | ]); 396 | 397 | grunt.registerTask('default', [ 398 | 'newer:jshint', 399 | 'test', 400 | 'build' 401 | ]); 402 | }; 403 | -------------------------------------------------------------------------------- /app/templates/_bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.0", 4 | "dependencies": {<% if (requireJS) { %> 5 | "requirejs": "~2.1.9", 6 | "almond": "latest",<% } %><% if (includeModernizr) { %> 7 | "modernizr": "~2.6.2",<% } %> 8 | "react": "~0.5.1" 9 | }, 10 | "devDependencies": {} 11 | } 12 | -------------------------------------------------------------------------------- /app/templates/_package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "<%= _.slugify(appname) %>", 3 | "version": "0.0.1", 4 | "dependencies": {}, 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-copy": "~0.4.1", 8 | "grunt-contrib-concat": "~0.3.0", 9 | "grunt-contrib-uglify": "~0.2.0", 10 | "grunt-contrib-compass": "~0.5.0", 11 | "grunt-contrib-jshint": "~0.6.3", 12 | "grunt-contrib-cssmin": "~0.6.0", 13 | "grunt-contrib-connect": "~0.5.0", 14 | "grunt-contrib-clean": "~0.5.0", 15 | "grunt-contrib-htmlmin": "~0.1.3",<% if (requireJS) { %> 16 | "grunt-bower-requirejs": "~0.7.0", 17 | "grunt-contrib-requirejs": "~0.4.1",<% } else { %> 18 | "grunt-bower-install": "~0.5.0",<% } %> 19 | "grunt-contrib-imagemin": "~0.2.0", 20 | "grunt-contrib-watch": "~0.5.2",<% if (testFramework === 'jasmine') { %> 21 | "grunt-contrib-jasmine": "~0.4.2",<% } %> 22 | "grunt-react": "~0.5.0", 23 | "grunt-rev": "~0.1.0", 24 | "grunt-autoprefixer": "~0.2.0", 25 | "grunt-usemin": "~2.0.0",<% if (testFramework === 'mocha') { %> 26 | "grunt-mocha": "~0.4.0",<% } %><% if (includeModernizr) { %> 27 | "grunt-modernizr": "~0.3.0",<% } %> 28 | "grunt-newer": "~0.5.4", 29 | "grunt-svgmin": "~0.2.0", 30 | "grunt-concurrent": "~0.3.0", 31 | "load-grunt-tasks": "~0.1.0", 32 | "time-grunt": "~0.1.1", 33 | "jshint-stylish": "~0.1.3" 34 | }, 35 | "engines": { 36 | "node": ">=0.8.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/templates/app-require.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 'use strict'; 3 | define([], function () { 4 | return React.createClass({ 5 | getInitialState: function() { 6 | return {message: 'Hello World!'}; 7 | }, 8 | goodbye: function(event) { 9 | this.setState({message: 'Goodbye World.'}); 10 | }, 11 | render: function() { 12 | return ( 13 |

{this.state.message}

14 | ); 15 | } 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /app/templates/app.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 'use strict'; 3 | var HelloWorld = React.createClass({ 4 | getInitialState: function() { 5 | return {message: 'Hello World!'}; 6 | }, 7 | goodbye: function(event) { 8 | this.setState({message: 'Goodbye World.'}); 9 | }, 10 | render: function() { 11 | return ( 12 |

{this.state.message}

13 | ); 14 | } 15 | }); 16 | 17 | React.renderComponent( 18 | , 19 | document.getElementById('app') 20 | ); 21 | -------------------------------------------------------------------------------- /app/templates/bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "app/bower_components" 3 | } 4 | -------------------------------------------------------------------------------- /app/templates/editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | 10 | # Change these settings to your own preference 11 | indent_style = space 12 | indent_size = 4 13 | 14 | # We recommend you to keep these unchanged 15 | end_of_line = lf 16 | charset = utf-8 17 | trim_trailing_whitespace = true 18 | insert_final_newline = true 19 | 20 | [*.md] 21 | trim_trailing_whitespace = false 22 | -------------------------------------------------------------------------------- /app/templates/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nemophrost/generator-react/6b9e82fdbc088fdc58e4f01c9dc4240dcbfcad30/app/templates/favicon.ico -------------------------------------------------------------------------------- /app/templates/gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto -------------------------------------------------------------------------------- /app/templates/gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .tmp 4 | .sass-cache 5 | app/bower_components 6 | -------------------------------------------------------------------------------- /app/templates/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 | 90 | 91 | Header set X-UA-Compatible "IE=edge" 92 | # `mod_headers` can't match based on the content-type, however, we only 93 | # want to send this header for HTML pages and not for the other resources 94 | 95 | Header unset X-UA-Compatible 96 | 97 | 98 | 99 | # ------------------------------------------------------------------------------ 100 | # | Cookie setting from iframes | 101 | # ------------------------------------------------------------------------------ 102 | 103 | # Allow cookies to be set from iframes in IE. 104 | 105 | # 106 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" 107 | # 108 | 109 | # ------------------------------------------------------------------------------ 110 | # | Screen flicker | 111 | # ------------------------------------------------------------------------------ 112 | 113 | # Stop screen flicker in IE on CSS rollovers (this only works in 114 | # combination with the `ExpiresByType` directives for images from below). 115 | 116 | # BrowserMatch "MSIE" brokenvary=1 117 | # BrowserMatch "Mozilla/4.[0-9]{2}" brokenvary=1 118 | # BrowserMatch "Opera" !brokenvary 119 | # SetEnvIf brokenvary 1 force-no-vary 120 | 121 | 122 | # ############################################################################## 123 | # # MIME TYPES AND ENCODING # 124 | # ############################################################################## 125 | 126 | # ------------------------------------------------------------------------------ 127 | # | Proper MIME types for all files | 128 | # ------------------------------------------------------------------------------ 129 | 130 | 131 | 132 | # Audio 133 | AddType audio/mp4 m4a f4a f4b 134 | AddType audio/ogg oga ogg 135 | 136 | # JavaScript 137 | # Normalize to standard type (it's sniffed in IE anyways): 138 | # http://tools.ietf.org/html/rfc4329#section-7.2 139 | AddType application/javascript js jsonp 140 | AddType application/json json 141 | 142 | # Video 143 | AddType video/mp4 mp4 m4v f4v f4p 144 | AddType video/ogg ogv 145 | AddType video/webm webm 146 | AddType video/x-flv flv 147 | 148 | # Web fonts 149 | AddType application/font-woff woff 150 | AddType application/vnd.ms-fontobject eot 151 | 152 | # Browsers usually ignore the font MIME types and sniff the content, 153 | # however, Chrome shows a warning if other MIME types are used for the 154 | # following fonts. 155 | AddType application/x-font-ttf ttc ttf 156 | AddType font/opentype otf 157 | 158 | # Make SVGZ fonts work on iPad: 159 | # https://twitter.com/FontSquirrel/status/14855840545 160 | AddType image/svg+xml svg svgz 161 | AddEncoding gzip svgz 162 | 163 | # Other 164 | AddType application/octet-stream safariextz 165 | AddType application/x-chrome-extension crx 166 | AddType application/x-opera-extension oex 167 | AddType application/x-shockwave-flash swf 168 | AddType application/x-web-app-manifest+json webapp 169 | AddType application/x-xpinstall xpi 170 | AddType application/xml atom rdf rss xml 171 | AddType image/webp webp 172 | AddType image/x-icon ico 173 | AddType text/cache-manifest appcache manifest 174 | AddType text/vtt vtt 175 | AddType text/x-component htc 176 | AddType text/x-vcard vcf 177 | 178 | 179 | 180 | # ------------------------------------------------------------------------------ 181 | # | UTF-8 encoding | 182 | # ------------------------------------------------------------------------------ 183 | 184 | # Use UTF-8 encoding for anything served as `text/html` or `text/plain`. 185 | AddDefaultCharset utf-8 186 | 187 | # Force UTF-8 for certain file formats. 188 | 189 | AddCharset utf-8 .atom .css .js .json .rss .vtt .webapp .xml 190 | 191 | 192 | 193 | # ############################################################################## 194 | # # URL REWRITES # 195 | # ############################################################################## 196 | 197 | # ------------------------------------------------------------------------------ 198 | # | Rewrite engine | 199 | # ------------------------------------------------------------------------------ 200 | 201 | # Turning on the rewrite engine and enabling the `FollowSymLinks` option is 202 | # necessary for the following directives to work. 203 | 204 | # If your web host doesn't allow the `FollowSymlinks` option, you may need to 205 | # comment it out and use `Options +SymLinksIfOwnerMatch` but, be aware of the 206 | # performance impact: http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks 207 | 208 | # Also, some cloud hosting services require `RewriteBase` to be set: 209 | # http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site 210 | 211 | 212 | Options +FollowSymlinks 213 | # Options +SymLinksIfOwnerMatch 214 | RewriteEngine On 215 | # RewriteBase / 216 | 217 | 218 | # ------------------------------------------------------------------------------ 219 | # | Suppressing / Forcing the "www." at the beginning of URLs | 220 | # ------------------------------------------------------------------------------ 221 | 222 | # The same content should never be available under two different URLs especially 223 | # not with and without "www." at the beginning. This can cause SEO problems 224 | # (duplicate content), therefore, you should choose one of the alternatives and 225 | # redirect the other one. 226 | 227 | # By default option 1 (no "www.") is activated: 228 | # http://no-www.org/faq.php?q=class_b 229 | 230 | # If you'd prefer to use option 2, just comment out all the lines from option 1 231 | # and uncomment the ones from option 2. 232 | 233 | # IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! 234 | 235 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 236 | 237 | # Option 1: rewrite www.example.com → example.com 238 | 239 | 240 | RewriteCond %{HTTPS} !=on 241 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] 242 | RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] 243 | 244 | 245 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 246 | 247 | # Option 2: rewrite example.com → www.example.com 248 | 249 | # Be aware that the following might not be a good idea if you use "real" 250 | # subdomains for certain parts of your website. 251 | 252 | # 253 | # RewriteCond %{HTTPS} !=on 254 | # RewriteCond %{HTTP_HOST} !^www\..+$ [NC] 255 | # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] 256 | # 257 | 258 | 259 | # ############################################################################## 260 | # # SECURITY # 261 | # ############################################################################## 262 | 263 | # ------------------------------------------------------------------------------ 264 | # | Content Security Policy (CSP) | 265 | # ------------------------------------------------------------------------------ 266 | 267 | # You can mitigate the risk of cross-site scripting and other content-injection 268 | # attacks by setting a Content Security Policy which whitelists trusted sources 269 | # of content for your site. 270 | 271 | # The example header below allows ONLY scripts that are loaded from the current 272 | # site's origin (no inline scripts, no CDN, etc). This almost certainly won't 273 | # work as-is for your site! 274 | 275 | # To get all the details you'll need to craft a reasonable policy for your site, 276 | # read: http://html5rocks.com/en/tutorials/security/content-security-policy (or 277 | # see the specification: http://w3.org/TR/CSP). 278 | 279 | # 280 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'" 281 | # 282 | # Header unset Content-Security-Policy 283 | # 284 | # 285 | 286 | # ------------------------------------------------------------------------------ 287 | # | File access | 288 | # ------------------------------------------------------------------------------ 289 | 290 | # Block access to directories without a default document. 291 | # Usually you should leave this uncommented because you shouldn't allow anyone 292 | # to surf through every directory on your server (which may includes rather 293 | # private places like the CMS's directories). 294 | 295 | 296 | Options -Indexes 297 | 298 | 299 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 300 | 301 | # Block access to hidden files and directories. 302 | # This includes directories used by version control systems such as Git and SVN. 303 | 304 | 305 | RewriteCond %{SCRIPT_FILENAME} -d [OR] 306 | RewriteCond %{SCRIPT_FILENAME} -f 307 | RewriteRule "(^|/)\." - [F] 308 | 309 | 310 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 311 | 312 | # Block access to backup and source files. 313 | # These files may be left by some text editors and can pose a great security 314 | # danger when anyone has access to them. 315 | 316 | 317 | Order allow,deny 318 | Deny from all 319 | Satisfy All 320 | 321 | 322 | # ------------------------------------------------------------------------------ 323 | # | Secure Sockets Layer (SSL) | 324 | # ------------------------------------------------------------------------------ 325 | 326 | # Rewrite secure requests properly to prevent SSL certificate warnings, e.g.: 327 | # prevent `https://www.example.com` when your certificate only allows 328 | # `https://secure.example.com`. 329 | 330 | # 331 | # RewriteCond %{SERVER_PORT} !^443 332 | # RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] 333 | # 334 | 335 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 336 | 337 | # Force client-side SSL redirection. 338 | 339 | # If a user types "example.com" in his browser, the above rule will redirect him 340 | # to the secure version of the site. That still leaves a window of opportunity 341 | # (the initial HTTP connection) for an attacker to downgrade or redirect the 342 | # request. The following header ensures that browser will ONLY connect to your 343 | # server via HTTPS, regardless of what the users type in the address bar. 344 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ 345 | 346 | # 347 | # Header set Strict-Transport-Security max-age=16070400; 348 | # 349 | 350 | # ------------------------------------------------------------------------------ 351 | # | Server software information | 352 | # ------------------------------------------------------------------------------ 353 | 354 | # Avoid displaying the exact Apache version number, the description of the 355 | # generic OS-type and the information about Apache's compiled-in modules. 356 | 357 | # ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! 358 | 359 | # ServerTokens Prod 360 | 361 | 362 | # ############################################################################## 363 | # # WEB PERFORMANCE # 364 | # ############################################################################## 365 | 366 | # ------------------------------------------------------------------------------ 367 | # | Compression | 368 | # ------------------------------------------------------------------------------ 369 | 370 | 371 | 372 | # Force compression for mangled headers. 373 | # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping 374 | 375 | 376 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding 377 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding 378 | 379 | 380 | 381 | # Compress all output labeled with one of the following MIME-types 382 | # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` 383 | # and can remove the `` and `` lines 384 | # as `AddOutputFilterByType` is still in the core directives). 385 | 386 | AddOutputFilterByType DEFLATE application/atom+xml \ 387 | application/javascript \ 388 | application/json \ 389 | application/rss+xml \ 390 | application/vnd.ms-fontobject \ 391 | application/x-font-ttf \ 392 | application/x-web-app-manifest+json \ 393 | application/xhtml+xml \ 394 | application/xml \ 395 | font/opentype \ 396 | image/svg+xml \ 397 | image/x-icon \ 398 | text/css \ 399 | text/html \ 400 | text/plain \ 401 | text/x-component \ 402 | text/xml 403 | 404 | 405 | 406 | 407 | # ------------------------------------------------------------------------------ 408 | # | Content transformations | 409 | # ------------------------------------------------------------------------------ 410 | 411 | # Prevent some of the mobile network providers from modifying the content of 412 | # your site: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. 413 | 414 | # 415 | # Header set Cache-Control "no-transform" 416 | # 417 | 418 | # ------------------------------------------------------------------------------ 419 | # | ETag removal | 420 | # ------------------------------------------------------------------------------ 421 | 422 | # Since we're sending far-future expires headers (see below), ETags can 423 | # be removed: http://developer.yahoo.com/performance/rules.html#etags. 424 | 425 | # `FileETag None` is not enough for every server. 426 | 427 | Header unset ETag 428 | 429 | 430 | FileETag None 431 | 432 | # ------------------------------------------------------------------------------ 433 | # | Expires headers (for better cache control) | 434 | # ------------------------------------------------------------------------------ 435 | 436 | # The following expires headers are set pretty far in the future. If you don't 437 | # control versioning with filename-based cache busting, consider lowering the 438 | # cache time for resources like CSS and JS to something like 1 week. 439 | 440 | 441 | 442 | ExpiresActive on 443 | ExpiresDefault "access plus 1 month" 444 | 445 | # CSS 446 | ExpiresByType text/css "access plus 1 year" 447 | 448 | # Data interchange 449 | ExpiresByType application/json "access plus 0 seconds" 450 | ExpiresByType application/xml "access plus 0 seconds" 451 | ExpiresByType text/xml "access plus 0 seconds" 452 | 453 | # Favicon (cannot be renamed!) 454 | ExpiresByType image/x-icon "access plus 1 week" 455 | 456 | # HTML components (HTCs) 457 | ExpiresByType text/x-component "access plus 1 month" 458 | 459 | # HTML 460 | ExpiresByType text/html "access plus 0 seconds" 461 | 462 | # JavaScript 463 | ExpiresByType application/javascript "access plus 1 year" 464 | 465 | # Manifest files 466 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" 467 | ExpiresByType text/cache-manifest "access plus 0 seconds" 468 | 469 | # Media 470 | ExpiresByType audio/ogg "access plus 1 month" 471 | ExpiresByType image/gif "access plus 1 month" 472 | ExpiresByType image/jpeg "access plus 1 month" 473 | ExpiresByType image/png "access plus 1 month" 474 | ExpiresByType video/mp4 "access plus 1 month" 475 | ExpiresByType video/ogg "access plus 1 month" 476 | ExpiresByType video/webm "access plus 1 month" 477 | 478 | # Web feeds 479 | ExpiresByType application/atom+xml "access plus 1 hour" 480 | ExpiresByType application/rss+xml "access plus 1 hour" 481 | 482 | # Web fonts 483 | ExpiresByType application/font-woff "access plus 1 month" 484 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month" 485 | ExpiresByType application/x-font-ttf "access plus 1 month" 486 | ExpiresByType font/opentype "access plus 1 month" 487 | ExpiresByType image/svg+xml "access plus 1 month" 488 | 489 | 490 | 491 | # ------------------------------------------------------------------------------ 492 | # | Filename-based cache busting | 493 | # ------------------------------------------------------------------------------ 494 | 495 | # If you're not using a build process to manage your filename version revving, 496 | # you might want to consider enabling the following directives to route all 497 | # requests such as `/css/style.12345.css` to `/css/style.css`. 498 | 499 | # To understand why this is important and a better idea than `*.css?v231`, read: 500 | # http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring 501 | 502 | # 503 | # RewriteCond %{REQUEST_FILENAME} !-f 504 | # RewriteCond %{REQUEST_FILENAME} !-d 505 | # RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpg|gif)$ $1.$3 [L] 506 | # 507 | 508 | # ------------------------------------------------------------------------------ 509 | # | File concatenation | 510 | # ------------------------------------------------------------------------------ 511 | 512 | # Allow concatenation from within specific CSS and JS files, e.g.: 513 | # Inside of `script.combined.js` you could have 514 | # 515 | # 516 | # and they would be included into this single file. 517 | 518 | # 519 | # 520 | # Options +Includes 521 | # AddOutputFilterByType INCLUDES application/javascript application/json 522 | # SetOutputFilter INCLUDES 523 | # 524 | # 525 | # Options +Includes 526 | # AddOutputFilterByType INCLUDES text/css 527 | # SetOutputFilter INCLUDES 528 | # 529 | # 530 | 531 | # ------------------------------------------------------------------------------ 532 | # | Persistent connections | 533 | # ------------------------------------------------------------------------------ 534 | 535 | # Allow multiple requests to be sent over the same TCP connection: 536 | # http://httpd.apache.org/docs/current/en/mod/core.html#keepalive. 537 | 538 | # Enable if you serve a lot of static content but, be aware of the 539 | # possible disadvantages! 540 | 541 | # 542 | # Header set Connection Keep-Alive 543 | # 544 | -------------------------------------------------------------------------------- /app/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <%= appname %> 10 | 11 | 12 | 13 | 14 | 15 | <% if (includeModernizr) { %> 16 | 17 | 18 | <% } %> 19 | <% if (reactAddons) { %> 20 | 21 | 22 | 23 | <% } else { %> 24 | 25 | 26 | 27 | <% } %> 28 | <% if (requireJS) { %> 29 | 30 | 31 | 32 | <% } %> 33 | 34 | 35 |
36 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | <% if (requireJS) { %> 46 | 47 | 48 | 49 | <% } else { %> 50 | 51 | 52 | 53 | <% } %> 54 | 55 | 56 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /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": 4, 11 | "latedef": true, 12 | "newcap": true, 13 | "noarg": true, 14 | "quotmark": "single", 15 | "undef": true, 16 | "unused": true, 17 | "strict": true, 18 | "trailing": true, 19 | "smarttabs": true, 20 | "jquery": true 21 | } 22 | -------------------------------------------------------------------------------- /app/templates/main-require.jsx: -------------------------------------------------------------------------------- 1 | /** @jsx React.DOM */ 2 | 'use strict'; 3 | 4 | require.config({ 5 | baseUrl: 'scripts', 6 | paths: { 7 | react: 'script/react.min' 8 | }, 9 | shim: { 10 | react: { 11 | exports: 'React' 12 | } 13 | } 14 | }); 15 | 16 | require(['app'], function (App) { 17 | // use app here 18 | React.renderComponent( 19 | , 20 | document.getElementById('app') 21 | ); 22 | }); -------------------------------------------------------------------------------- /app/templates/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 | 24 | .browsehappy { 25 | margin: 0.2em 0; 26 | background: #ccc; 27 | color: #000; 28 | padding: 0.2em 0; 29 | } 30 | -------------------------------------------------------------------------------- /app/templates/robots.txt: -------------------------------------------------------------------------------- 1 | # robotstxt.org/ 2 | 3 | User-agent: * 4 | -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ### v0.0.2 (2014-05-02) 2 | 3 | - Fixed typos in package.json 4 | 5 | 6 | ### v0.0.1 (2013-11-23) 7 | 8 | - Initial release 9 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | See the [contributing docs](https://github.com/yeoman/yeoman/blob/master/contributing.md) 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "generator-react", 3 | "version": "0.0.2", 4 | "description": "Scaffold out a front-end web app with React", 5 | "keywords": [ 6 | "yeoman-generator", 7 | "web", 8 | "app", 9 | "front-end", 10 | "react" 11 | ], 12 | "homepage": "https://github.com/nemophrost/generator-react", 13 | "bugs": "https://github.com/nemophrost/generator-react/issues", 14 | "author": "Alma Madsen", 15 | "main": "app/index.js", 16 | "repository": { 17 | "type": "git", 18 | "url": "git://github.com/nemophrost/generator-react.git" 19 | }, 20 | "scripts": { 21 | "test": "mocha --reporter spec" 22 | }, 23 | "dependencies": { 24 | "yeoman-generator": "~0.18", 25 | "cheerio": "~0.12.1" 26 | }, 27 | "peerDependencies": { 28 | "yo": ">=1.0.0-rc.1.1", 29 | "generator-mocha": "~0.1.1" 30 | }, 31 | "devDependencies": { 32 | "mocha": "~1.12.0" 33 | }, 34 | "engines": { 35 | "node": ">=0.8.0", 36 | "npm": ">=1.2.10" 37 | }, 38 | "licenses": [ 39 | { 40 | "type": "BSD" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | /*global describe, beforeEach, it*/ 2 | 3 | var path = require('path'); 4 | var helpers = require('yeoman-generator').test; 5 | var assert = require('assert'); 6 | 7 | 8 | describe('Webapp generator test', 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.webapp = helpers.createGenerator('webapp:app', [ 16 | '../../app', [ 17 | helpers.createDummyGenerator(), 18 | 'mocha:app' 19 | ] 20 | ]); 21 | done(); 22 | }.bind(this)); 23 | }); 24 | 25 | it('the generator can be required without throwing', function () { 26 | // not testing the actual run of generators yet 27 | this.app = require('../app'); 28 | }); 29 | 30 | it('creates expected files', function (done) { 31 | var expected = [ 32 | ['bower.json', /"name": "temp"/], 33 | ['package.json', /"name": "temp"/], 34 | ['Gruntfile.js', /coffee:/], 35 | 'app/404.html', 36 | 'app/favicon.ico', 37 | 'app/robots.txt', 38 | 'app/index.html', 39 | 'app/scripts/hello.coffee', 40 | 'app/scripts/main.js', 41 | 'app/styles/main.scss' 42 | ]; 43 | 44 | helpers.mockPrompt(this.webapp, { 45 | features: ['compassBootstrap'] 46 | }); 47 | 48 | this.webapp.coffee = true; 49 | this.webapp.options['skip-install'] = true; 50 | this.webapp.run({}, function () { 51 | helpers.assertFiles(expected); 52 | done(); 53 | }); 54 | }); 55 | 56 | it('creates expected files in non-AMD non-coffee mode', function (done) { 57 | var expected = [ 58 | ['bower.json', /"name": "temp"/], 59 | ['package.json', /"name": "temp"/], 60 | 'Gruntfile.js', 61 | 'app/404.html', 62 | 'app/favicon.ico', 63 | 'app/robots.txt', 64 | 'app/index.html', 65 | 'app/scripts/main.js', 66 | 'app/styles/main.scss' 67 | ]; 68 | 69 | helpers.mockPrompt(this.webapp, { 70 | features: ['compassBootstrap'] 71 | }); 72 | 73 | this.webapp.coffee = false; 74 | this.webapp.options['skip-install'] = true; 75 | this.webapp.run({}, function () { 76 | helpers.assertFiles(expected); 77 | done(); 78 | }); 79 | }); 80 | 81 | it('creates expected files in AMD mode', function (done) { 82 | var expected= [ 83 | ['bower.json', /"name": "temp"/], 84 | ['package.json', /"name": "temp"/], 85 | 'Gruntfile.js', 86 | 'app/404.html', 87 | 'app/favicon.ico', 88 | 'app/robots.txt', 89 | 'app/index.html', 90 | 'app/scripts/main.js', 91 | 'app/styles/main.scss' 92 | ]; 93 | 94 | helpers.mockPrompt(this.webapp, { 95 | features: ['compassBootstrap'] 96 | }); 97 | 98 | this.webapp.options['skip-install'] = true; 99 | this.webapp.run({}, function () { 100 | helpers.assertFiles(expected); 101 | done(); 102 | }); 103 | }); 104 | }); 105 | --------------------------------------------------------------------------------