diff --git a/README.md b/README.md index ca18976e..63b220ab 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ This generator can also be further configured with the following command line fl --pug add pug engine support --hbs add handlebars engine support -H, --hogan add hogan.js engine support - -v, --view add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade) + -v, --view add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash|jsx) (defaults to jade) --no-view use static html instead of view engine -c, --css add stylesheet support (less|stylus|compass|sass) (defaults to plain css) --git add .gitignore diff --git a/bin/express-cli.js b/bin/express-cli.js index d0c80b7f..9239373b 100755 --- a/bin/express-cli.js +++ b/bin/express-cli.js @@ -52,7 +52,7 @@ program .option(' --pug', 'add pug engine support', renamedOption('--pug', '--view=pug')) .option(' --hbs', 'add handlebars engine support', renamedOption('--hbs', '--view=hbs')) .option('-H, --hogan', 'add hogan.js engine support', renamedOption('--hogan', '--view=hogan')) - .option('-v, --view ', 'add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)') + .option('-v, --view ', 'add view support (dust|ejs|hbs|hjs|jade|pug|twig|vash|jsx) (defaults to jade)') .option(' --no-view', 'use static html instead of view engine') .option('-c, --css ', 'add stylesheet support (less|stylus|compass|sass) (defaults to plain css)') .option(' --git', 'add .gitignore') @@ -238,6 +238,9 @@ function createApplication (name, dir) { case 'vash': copyTemplateMulti('views', dir + '/views', '*.vash') break + case 'jsx': + copyTemplateMulti('views', dir + '/views', '*.jsx') + break } } else { // Copy extra public files @@ -314,6 +317,15 @@ function createApplication (name, dir) { app.locals.view = { engine: 'vash' } pkg.dependencies.vash = '~0.12.6' break + case 'jsx': + app.locals.view = { + engine: 'jsx', + render: "require('express-react-views').createEngine()" + } + pkg.dependencies['express-react-views'] = '^0.11.0' + pkg.dependencies.react = '^16.13.1' + pkg.dependencies['react-dom'] = '^16.13.1' + break default: app.locals.view = false break diff --git a/templates/views/error.jsx b/templates/views/error.jsx new file mode 100644 index 00000000..0619bab8 --- /dev/null +++ b/templates/views/error.jsx @@ -0,0 +1,14 @@ +var React = require('react'); +var Layout = require('./layout'); + +function Index(props) { + return ( + +

{props.message}

+

{props.error.status}

+
{props.error.stack}
+
+ ); +} + +module.exports = Index; \ No newline at end of file diff --git a/templates/views/index.jsx b/templates/views/index.jsx new file mode 100644 index 00000000..6d003a14 --- /dev/null +++ b/templates/views/index.jsx @@ -0,0 +1,13 @@ +var React = require('react'); +var Layout = require('./layout'); + +function Index(props) { + return ( + +

{props.title}

+

Welcome to {props.title}

+
+ ); +} + +module.exports = Index; \ No newline at end of file diff --git a/templates/views/layout.jsx b/templates/views/layout.jsx new file mode 100644 index 00000000..a93da7c9 --- /dev/null +++ b/templates/views/layout.jsx @@ -0,0 +1,14 @@ +var React = require('react'); + +function Layout(props) { + return ( + + + {props.title} + + {props.children} + + ); +} + +module.exports = Layout; \ No newline at end of file diff --git a/test/cmd.js b/test/cmd.js index c0711a73..fc65ad62 100644 --- a/test/cmd.js +++ b/test/cmd.js @@ -1133,6 +1133,73 @@ describe('express(1)', function () { }) }) }) + + describe('jsx', function () { + var ctx = setupTestEnvironment(this.fullTitle()) + + it('should create basic app with jsx templates', function (done) { + run(ctx.dir, ['--view', 'jsx'], function (err, stdout) { + if (err) return done(err) + ctx.files = utils.parseCreatedFiles(stdout, ctx.dir) + assert.strictEqual(ctx.files.length, 16) + done() + }) + }) + + it('should have basic files', function () { + assert.notStrictEqual(ctx.files.indexOf('bin/www'), -1) + assert.notStrictEqual(ctx.files.indexOf('app.js'), -1) + assert.notStrictEqual(ctx.files.indexOf('package.json'), -1) + }) + + it('should have express-react-views, react, react-dom in package dependencies', function () { + var file = path.resolve(ctx.dir, 'package.json') + var contents = fs.readFileSync(file, 'utf8') + var dependencies = JSON.parse(contents).dependencies + assert.ok(typeof dependencies['express-react-views'] === 'string') + assert.ok(typeof dependencies.react === 'string') + assert.ok(typeof dependencies['react-dom'] === 'string') + }) + + it('should have jsx templates', function () { + assert.notStrictEqual(ctx.files.indexOf('views/error.jsx'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/index.jsx'), -1) + assert.notStrictEqual(ctx.files.indexOf('views/layout.jsx'), -1) + }) + + it('should have installable dependencies', function (done) { + this.timeout(NPM_INSTALL_TIMEOUT) + npmInstall(ctx.dir, done) + }) + + describe('npm start', function () { + before('start app', function () { + this.app = new AppRunner(ctx.dir) + }) + + after('stop app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.stop(done) + }) + + it('should start app', function (done) { + this.timeout(APP_START_STOP_TIMEOUT) + this.app.start(done) + }) + + it('should respond to HTTP request', function (done) { + request(this.app) + .get('/') + .expect(200, /Express<\/title>/, done) + }) + + it('should generate a 404 (not found)', function (done) { + request(this.app) + .get('/does_not_exist') + .expect(404, /<h1>Not Found<\/h1>/, done) + }) + }) + }) }) })