Squashed commit of the following:

commit 25ef9a176ee9bab902579f79415bd6047a77a62f
Author: Simon Bailey <simon@newtriks.com>
Date:   Thu May 15 19:51:45 2014 +0100

    Updated README

    Signed-off-by: Simon Bailey <simon@newtriks.com>

commit 1b0020c8fd248bc0dc892bed1f3e315867378274
Merge: d8fd494 c468b98
Author: Edd <accounts@edd.fm>
Date:   Sat Apr 26 11:13:52 2014 +0100

    Merged with Master

commit d8fd494478cb7fd0d97a47a90986f4c1b29eb996
Author: Edd <accounts@edd.fm>
Date:   Thu Apr 24 22:09:19 2014 +0100

    Trimming redundant options from Gruntfile

commit b5015ae42b0beb770ae1b146f152b5f38764987e
Author: Edd <accounts@edd.fm>
Date:   Sun Mar 30 21:32:14 2014 +0100

    Moved development mode to webpack-dev-server to imrove rebuild times

commit 7d31ade8085a8d415b95c67dba69ae5157ebf9b4
Author: Edd <accounts@edd.fm>
Date:   Wed Feb 26 00:18:56 2014 +0000

    Changed JSX filenames to .jsx over .js

commit 00faa6182b6cb4ae46b05dd12db1e73da4b47953
Author: Edd <accounts@edd.fm>
Date:   Mon Feb 24 23:39:18 2014 +0000

    Updated engines & Travis build targets

commit e58e0d70639f3c3e9acc7d085b6a795365a140a6
Author: Edd <accounts@edd.fm>
Date:   Mon Feb 24 23:26:04 2014 +0000

    Added auto generation of a template CSS file for a component

commit f6c67351aead570224b2457261d457a1954277dc
Author: Edd <accounts@edd.fm>
Date:   Mon Feb 24 00:06:42 2014 +0000

    Updated default app test

commit 996d769685d1a4f20ae2c4117422790bbc347594
Author: Edd <accounts@edd.fm>
Date:   Sun Feb 23 23:32:37 2014 +0000

    Added test for default main component (currently identical to any other component tests)

commit 31dfcbaff6ee9aef339886897e053a339f98021b
Author: Edd <accounts@edd.fm>
Date:   Sun Feb 23 22:54:04 2014 +0000

    Moved webpack configuration to a separate file

    - Added webpack config file
    - Added Uglify to webpack config
    - Added source maps in webpack config

    Moved entry file back in to Gruntfile

commit 6b3a3e92b80f3121e1128e4f166cf36aa32cfa26
Author: Edd <accounts@edd.fm>
Date:   Sun Feb 23 17:23:07 2014 +0000

    Added distribution folder & Grunt tasks to deal with it

    - Created Distribution build folder (script link broken)
    - Added grunt-contrib-copy
    - Added grunt-uglify
    - Bumped React version number
    - Switched source map types

Signed-off-by: Simon Bailey <simon@newtriks.com>
This commit is contained in:
Simon Bailey 2014-05-15 19:52:23 +01:00
parent c468b9892e
commit d6d216d05d
20 changed files with 262 additions and 116 deletions

1
.gitignore vendored
View File

@ -28,4 +28,5 @@ $RECYCLE.BIN/
# App specific
node_modules/
/test/temp-test/
/test/temp/

View File

@ -1,6 +1,5 @@
language: node_js
node_js:
- '0.8'
- '0.10'
before_install:
- currentfolder=${PWD##*/}

View File

@ -1,4 +1,4 @@
# generator-react-webpack [![Build Status](https://secure.travis-ci.org/newtriks/generator-react-webpack.png?branch=master)](https://travis-ci.org/newtriks/generator-react-webpack) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
# generator-react-webpack [![Build Status](https://secure.travis-ci.org/eddhannay/generator-react-webpack.png?branch=master)](https://travis-ci.org/eddhannay/generator-react-webpack) [![Built with Grunt](https://cdn.gruntjs.com/builtwith.png)](http://gruntjs.com/)
> Yeoman generator for [ReactJS](http://facebook.github.io/react/) - lets you quickly set up a project including karma test runner and [Webpack](http://webpack.github.io/) module system.
@ -54,7 +54,7 @@ Example:
yo react-webpack:component foo
```
Produces `src/scripts/components/Foo.js` (*javascript - JSX*):
Produces `src/scripts/components/Foo.jsx` (*javascript - JSX*):
```
/**
* @jsx React.DOM
@ -98,6 +98,14 @@ describe('Foo', function () {
});
```
And `src/styles/Foo.css`:
```
.Foo{
border: 1px dashed #f00;
}
```
## Testing
Running `grunt test` will run the unit tests with karma. Tests are written using [Jasmine](http://pivotal.github.io/jasmine/) by default.
@ -148,7 +156,7 @@ Each component is a module and can be required using the [Webpack](http://webpac
Out the box the [Gruntfile](http://gruntjs.com/api/grunt.file) is configured with the following:
1. **webpack**: uses the [grunt-webpack](https://github.com/webpack/grunt-webpack) plugin to load all required modules and output to a single JS file `src/scripts/main.js`. This is included in the `src/index.html` file by default and will reload in the browser as and when it is recompiled.
2. **watch**: uses the [grunt-watch](https://github.com/gruntjs/grunt-contrib-watch) plugin and watches for file changes. Livereload support is included by default and thus on file change the *webpack* task is run and the browser will auto update.
2. **webpack-dev-server**: uses the [webpack-dev-server](https://github.com/webpack/webpack-dev-server) to watch for file changes and also serve the webpack app in development.
3. **connect**: uses the [grunt-connect](https://github.com/gruntjs/grunt-contrib-connect) plugin to start a webserver at [localhost](http://localhost:8000).
4. **karma**: uses the [grunt-karma](https://github.com/karma-runner/grunt-karma) plugin to load the Karma configuration file `karma.conf.js` located in the project root. This will run all tests using [PhantomJS](http://phantomjs.org/) by default but supports many other browsers.
@ -167,7 +175,3 @@ Contributions are welcomed. When submitting a bugfix, write a test that exposes
## License
[BSD license](http://opensource.org/licenses/bsd-license.php)
[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/newtriks/generator-react-webpack/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

View File

@ -12,6 +12,7 @@ ComponentGenerator.prototype.createComponentFile = function createComponentFile(
this.generateSourceAndTest(
'Component',
'spec/Component',
'styles/Component',
'components'
);
};

View File

@ -1,4 +1,5 @@
'use strict';
var util = require('util');
var ScriptBase = require('../script-base.js');
@ -9,5 +10,6 @@ var MainGenerator = module.exports = function MainGenerator(args, options, confi
util.inherits(MainGenerator, ScriptBase);
MainGenerator.prototype.createAppFile = function createAppFile() {
this.appTemplate('App', 'scripts/components/'+this.scriptAppName);
this.appTemplate('App', 'scripts/components/' + this.scriptAppName);
this.testTemplate('spec/App', 'components/' + this.scriptAppName);
};

View File

@ -38,8 +38,7 @@
"yo": ">=1.0.0"
},
"engines": {
"node": ">=0.8.0",
"npm": ">=1.2.10"
"node": ">=0.10.0"
},
"licenses": [
{

View File

@ -8,7 +8,8 @@ var Generator = module.exports = function Generator() {
yeoman.generators.NamedBase.apply(this, arguments);
// Add capitalize mixin
this._.mixin({ 'capitalize': generalUtils.capitalize });
this._.mixin({ 'capitalize': generalUtils.capitalize });
this._.mixin({ 'lowercase': generalUtils.lowercase });
this.appname = path.basename(process.cwd());
@ -24,8 +25,16 @@ var Generator = module.exports = function Generator() {
this.env.options.testPath = this.env.options.testPath || 'test/spec';
}
var sourceRoot = '/templates/javascript';
if (typeof this.env.options.stylesPath === 'undefined') {
this.env.options.stylesPath = this.env.options.stylesPath || 'src/styles';
}
var sourceRoot = '/templates/';
this.scriptSuffix = '.js';
this.reactSuffix = '.jsx';
var stylesRoot = '/templates/styles';
this.stylesSuffix = '.css';
this.sourceRoot(path.join(__dirname, sourceRoot));
};
@ -34,8 +43,8 @@ util.inherits(Generator, yeoman.generators.NamedBase);
Generator.prototype.appTemplate = function (src, dest) {
yeoman.generators.Base.prototype.template.apply(this, [
src + this.scriptSuffix,
path.join(this.env.options.appPath, dest) + this.scriptSuffix
path.join('javascript', src + this.reactSuffix),
path.join(this.env.options.appPath, dest) + this.reactSuffix
]);
};
@ -46,6 +55,14 @@ Generator.prototype.testTemplate = function (src, dest) {
]);
};
Generator.prototype.stylesTemplate = function (src, dest) {
console.log(src);
yeoman.generators.Base.prototype.template.apply(this, [
src + this.stylesSuffix,
path.join(this.env.options.stylesPath, dest) + this.stylesSuffix
]);
};
Generator.prototype.htmlTemplate = function (src, dest) {
yeoman.generators.Base.prototype.template.apply(this, [
src,
@ -53,7 +70,8 @@ Generator.prototype.htmlTemplate = function (src, dest) {
]);
};
Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, targetDirectory) {
Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate, stylesTemplate, targetDirectory) {
this.appTemplate(appTemplate, path.join('scripts', targetDirectory, this._.capitalize(this.name)));
this.testTemplate(testTemplate, path.join(targetDirectory, this._.capitalize(this.name)));
this.stylesTemplate(stylesTemplate, path.join(this._.capitalize(this.name)));
};

View File

@ -1,101 +1,51 @@
'use strict';
var LIVERELOAD_PORT = 35729;
var lrSnippet = require('connect-livereload')({
port: LIVERELOAD_PORT
});
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
var webpackDistConfig = require('./webpack.dist.config.js'),
webpackDevConfig = require('./webpack.config.js');
module.exports = function (grunt) {
// Let *load-grunt-tasks* require everything
require('load-grunt-tasks')(grunt);
// Read configuration from package.json
var pkgConfig = grunt.file.readJSON('package.json');
var jshintConfig = grunt.file.readJSON('.jshintrc');
var loaders = [{
test: /\.css$/,
loader: 'style!css'
}, {
test: /\.gif/,
loader: 'url-loader?limit=10000&minetype=image/gif'
}, {
test: /\.jpg/,
loader: 'url-loader?limit=10000&minetype=image/jpg'
}, {
test: /\.png/,
loader: 'url-loader?limit=10000&minetype=image/png'
}, {
test: /\.js$/,
loader: 'jsx-loader'
}];
grunt.initConfig({
pkg: pkgConfig,
webpack: {
development: {
entry: './<%= pkg.src %>/scripts/components/<%= pkg.mainInput %>.js',
output: {
path: '<%= pkg.src %>/scripts/',
filename: '<%= pkg.mainOutput %>.js'
},
debug: true,
cache: true,
stats: {
colors: true,
reasons: true
},
jshint: grunt.util._.merge(jshintConfig, {
emitErrors: false,
failOnHint: false
}),
module: {
preLoaders: [{
test: '\\.js$',
exclude: 'node_modules',
loader: 'jshint'
}],
loaders: loaders
}
options: webpackDistConfig,
dist: {
cache: false
}
},
watch: {
webpack: {
files: ['<%= pkg.src %>/scripts/{,*/}*.js',
'<%= pkg.src %>/styles/{,*/}*.css',
'!<%= pkg.src %>/scripts/<%= pkg.mainOutput %>.js'
],
tasks: ['webpack:development']
},
livereload: {
options: {
livereload: LIVERELOAD_PORT
},
files: [
'<%= pkg.src %>/{,*/}*.html',
'<%= pkg.src %>/scripts/<%= pkg.mainOutput %>.js'
]
}
},
connect: {
'webpack-dev-server': {
options: {
port: 8000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost'
webpack: webpackDevConfig,
publicPath: '/scripts/',
contentBase: './<%= pkg.src %>/',
},
livereload: {
options: {
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, pkgConfig.src)
];
}
}
start: {
keepAlive: true,
}
},
connect: {
options: {
port: 8000
},
dist: {
options: {
keepalive: true,
middleware: function (connect) {
return [
mountFolder(connect, pkgConfig.dist)
@ -104,34 +54,72 @@ module.exports = function (grunt) {
}
}
},
open: {
server: {
url: 'http://localhost:<%= connect.options.port %>'
options: {
delay: 500
},
dev: {
path: 'http://localhost:<%= connect.options.port %>/webpack-dev-server/'
},
dist: {
path: 'http://localhost:<%= connect.options.port %>/'
}
},
karma: {
unit: {
configFile: 'karma.conf.js'
}
},
copy: {
dist: {
files: [
// includes files within path
{
flatten: true,
expand: true,
src: ['<%= pkg.src %>/*'],
dest: '<%= pkg.dist %>/',
filter: 'isFile'
},
{
flatten: true,
expand: true,
src: ['<%= pkg.src %>/images/*'],
dest: '<%= pkg.dist %>/images/'
},
]
}
},
clean: {
dist: {
files: [{
dot: true,
src: [
'<%= pkg.dist %>'
]
}]
}
}
});
grunt.registerTask('serve', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'open', 'connect:dist:keepalive']);
return grunt.task.run(['build', 'open:dist', 'connect:dist']);
}
grunt.task.run([
'connect:livereload',
'webpack:development',
'open',
'watch'
'open:dev',
'webpack-dev-server'
]);
});
grunt.registerTask('test', ['karma']);
grunt.registerTask('build', []);
grunt.registerTask('build', ['clean', 'copy', 'webpack']);
grunt.registerTask('default', []);
};

View File

@ -11,15 +11,13 @@
},
"devDependencies": {
"grunt": "~0.4.4",
"load-grunt-tasks": "~0.2.1",
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-connect": "~0.6.0",
"connect-livereload": "~0.3.1",
"load-grunt-tasks": "~0.4.0",
"grunt-contrib-connect": "~0.7.1",
"webpack": "~1.1.2",
"jsx-loader": "~0.9.0",
"grunt-webpack": "~1.0.0",
"style-loader": "~0.6.0",
"url-loader": "~0.5.2",
"style-loader": "~0.6.3",
"url-loader": "~0.5.4",
"css-loader": "~0.6.6",
"karma-script-launcher": "~0.1.0",
"karma-chrome-launcher": "~0.1.2",
@ -29,8 +27,10 @@
"karma": "~0.10.9",
"grunt-karma": "~0.6.2",
"karma-webpack-plugin": "~1.0.0",
"webpack-dev-server": "~1.0.2",
"grunt-open": "~0.2.2",
"jshint-loader": "~0.6.0"
"webpack-dev-server": "~1.2.4",
"grunt-open": "~0.2.3",
"jshint-loader": "~0.6.0",
"grunt-contrib-copy": "~0.5.0",
"grunt-contrib-clean": "~0.5.0"
}
}

View File

@ -29,4 +29,5 @@ $RECYCLE.BIN/
node_modules/
.tmp
dist
/src/scripts/main.js

View File

@ -12,7 +12,7 @@
<p class="browsehappy">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your experience.</p>
<![endif]-->
<div id="content">
<h1>If you can see this, something is broken (or JS is not enabled).</h1>
<h1>If you can see this, something is broken (or JS is not enabled)!!.</h1>
</div>
<script type="text/javascript" src="scripts/main.js"></script>
</body>

View File

@ -27,7 +27,7 @@ module.exports = function (config) {
test: /\.png/,
loader: 'url-loader?limit=10000&minetype=image/png'
}, {
test: /\.js$/,
test: /\.jsx$/,
loader: 'jsx-loader'
}]
}

View File

@ -0,0 +1,49 @@
/*
* Webpack development server configuration
*
* This file is set up for serving the webpak-dev-server, which will watch for changes and recompile as required if
* the subfolder /webpack-dev-server/ is visited. Visiting the root will not automatically reload.
*/
'use strict';
module.exports = {
output: {
filename: 'main.js'
},
cache: true,
debug: true,
devtool: false,
entry: './src/scripts/components/<%= pkg.mainInput %>.jsx',
stats: {
colors: true,
reasons: true
},
module: {
preLoaders: [{
test: '\\.js$',
exclude: 'node_modules',
loader: 'jshint'
}],
loaders: [{
test: /\.css$/,
loader: 'style!css'
}, {
test: /\.gif/,
loader: 'url-loader?limit=10000&minetype=image/gif'
}, {
test: /\.jpg/,
loader: 'url-loader?limit=10000&minetype=image/jpg'
}, {
test: /\.png/,
loader: 'url-loader?limit=10000&minetype=image/png'
}, {
test: /\.jsx$/,
loader: 'jsx-loader'
}]
}
};

View File

@ -0,0 +1,60 @@
/*
* Webpack distribution configuration
*
* This file is set up for serving the distribution version. It will be compiled to dist/ by default
*/
'use strict';
var webpack = require('webpack');
module.exports = {
output: {
publicPatch: 'dist/',
path: 'dist/scripts/',
filename: 'main.js'
},
debug: false,
devtool: false,
entry: './src/scripts/components/<%= pkg.mainInput %>.jsx',
stats: {
colors: true,
reasons: false
},
plugins: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.AggressiveMergingPlugin()
],
module: {
preLoaders: [{
test: '\\.js$',
exclude: 'node_modules',
loader: 'jshint'
}],
loaders: [
{
test: /\.css$/,
loader: 'style!css'
}, {
test: /\.gif/,
loader: 'url-loader?limit=10000&minetype=image/gif'
}, {
test: /\.jpg/,
loader: 'url-loader?limit=10000&minetype=image/jpg'
}, {
test: /\.png/,
loader: 'url-loader?limit=10000&minetype=image/png'
}, {
test: /\.jsx$/,
loader: 'jsx-loader'
}
]
}
};

View File

@ -5,6 +5,7 @@
'use strict';
var React = require('react/addons');
require('../../styles/<%= classedName %>.css');
var <%= classedName %> = React.createClass({
/*jshint ignore:start */

18
templates/spec/App.js Normal file
View File

@ -0,0 +1,18 @@
'use strict';
describe('<%= classedName %>', function () {
var <%= scriptAppName %>, component;
beforeEach(function () {
var container = document.createElement('div');
container.id = 'content';
document.body.appendChild(container);
<%= scriptAppName %> = require('../../../src/scripts/components/<%= scriptAppName %>.jsx');
component = <%= scriptAppName %>();
});
it('should create a new instance of <%= scriptAppName %>', function () {
expect(component).toBeDefined();
});
});

View File

@ -4,7 +4,7 @@ describe('<%= classedName %>', function () {
var <%= classedName %>, component;
beforeEach(function () {
<%= classedName %> = require('../../../src/scripts/components/<%= classedName %>');
<%= classedName %> = require('../../../src/scripts/components/<%= classedName %>.jsx');
component = <%= classedName %>();
});

View File

@ -0,0 +1,3 @@
.<%= classedName %>{
border: 1px dashed #f00;
}

View File

@ -39,12 +39,14 @@ describe('react-webpack generator', function () {
'src/styles/main.css',
'src/index.html',
'Gruntfile.js',
'webpack.config.js',
'karma.conf.js',
'package.json',
'package.json',
'src/scripts/components/TempTestApp.js',
'src/scripts/components/TempTestApp.jsx',
'test/helpers/phantomjs-shims.js',
'test/helpers/react/addons.js'
'test/helpers/react/addons.js',
'test/spec/components/TempTestApp.js',
];
react.run({}, function () {
@ -84,7 +86,7 @@ describe('react-webpack generator', function () {
//var Foo = React.createClass({
reactGenerator.run([], function () {
helpers.assertFiles([
[path.join('src/scripts', targetDirectory, name + '.js'), new RegExp('var ' + scriptNameFn(name) + suffix, 'g')],
[path.join('src/scripts', targetDirectory, name + '.jsx'), new RegExp('var ' + scriptNameFn(name) + suffix, 'g')],
[path.join('test/spec', targetDirectory, name + '.js'), new RegExp('describe\\(\'' + specNameFn(name) + suffix + '\'', 'g')]
]);
done();