diff --git a/bin/express-cli.js b/bin/express-cli.js index 380a447d..bb1a1938 100755 --- a/bin/express-cli.js +++ b/bin/express-cli.js @@ -1,5 +1,6 @@ #!/usr/bin/env node +var exec = require('child_process').exec var ejs = require('ejs') var fs = require('fs') var minimatch = require('minimatch') @@ -103,214 +104,234 @@ function createApplication (name, dir, options, done) { } } + var www = {} + var app = {} // JavaScript - var app = loadTemplate('js/app.js') - var www = loadTemplate('js/www') - - // App name - www.locals.name = name - - // App modules - app.locals.localModules = Object.create(null) - app.locals.modules = Object.create(null) - app.locals.mounts = [] - app.locals.uses = [] - - // Request logger - app.locals.modules.logger = 'morgan' - app.locals.uses.push("logger('dev')") - pkg.dependencies.morgan = '~1.10.0' - - // Body parsers - app.locals.uses.push('express.json()') - app.locals.uses.push('express.urlencoded({ extended: false })') - - // Cookie parser - app.locals.modules.cookieParser = 'cookie-parser' - app.locals.uses.push('cookieParser()') - pkg.dependencies['cookie-parser'] = '~1.4.5' - - if (dir !== '.') { - mkdir(dir, '.') - } + exec('node -v', function (errorval, stdout, stderr) { + if (errorval !== null) { + console.log('Error : ' + errorval) + } + if (stdout) { + var nodeVersion = parseFloat(stdout.split('v')[1]) + if (nodeVersion >= 20) { + app = loadTemplate('js/es6appandwww/app.js') + www = loadTemplate('js/es6appandwww/www') + } else { + app = loadTemplate('js/app.js') + www = loadTemplate('js/www') + } + } - mkdir(dir, 'public') - mkdir(dir, 'public/javascripts') - mkdir(dir, 'public/images') - mkdir(dir, 'public/stylesheets') - - // copy css templates - switch (options.css) { - case 'less': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.less') - break - case 'stylus': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl') - break - case 'compass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss') - break - case 'sass': - copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass') - break - default: - copyTemplateMulti('css', dir + '/public/stylesheets', '*.css') - break - } + // App name + www.locals.name = name + + // App modules + app.locals.localModules = Object.create(null) + app.locals.modules = Object.create(null) + app.locals.mounts = [] + app.locals.uses = [] + + // Request logger + app.locals.modules.logger = 'morgan' + app.locals.uses.push("logger('dev')") + pkg.dependencies.morgan = '~1.10.0' + + // Body parsers + app.locals.uses.push('express.json()') + app.locals.uses.push('express.urlencoded({ extended: false })') + + // Cookie parser + app.locals.modules.cookieParser = 'cookie-parser' + app.locals.uses.push('cookieParser()') + pkg.dependencies['cookie-parser'] = '~1.4.5' + + if (dir !== '.') { + mkdir(dir, '.') + } + + mkdir(dir, 'public') + mkdir(dir, 'public/javascripts') + mkdir(dir, 'public/images') + mkdir(dir, 'public/stylesheets') + + // copy css templates + switch (options.css) { + case 'less': + copyTemplateMulti('css', dir + '/public/stylesheets', '*.less') + break + case 'stylus': + copyTemplateMulti('css', dir + '/public/stylesheets', '*.styl') + break + case 'compass': + copyTemplateMulti('css', dir + '/public/stylesheets', '*.scss') + break + case 'sass': + copyTemplateMulti('css', dir + '/public/stylesheets', '*.sass') + break + default: + copyTemplateMulti('css', dir + '/public/stylesheets', '*.css') + break + } - // copy route templates - mkdir(dir, 'routes') - copyTemplateMulti('js/routes', dir + '/routes', '*.js') + // copy route templates + mkdir(dir, 'routes') - if (options.view) { - // Copy view templates - mkdir(dir, 'views') - pkg.dependencies['http-errors'] = '~1.7.2' + if (nodeVersion >= 20) { + copyTemplateMulti('js/es6routes', dir + '/routes', '*.js') + } else { + copyTemplateMulti('js/routes', dir + '/routes', '*.js') + } + + if (options.view) { + // Copy view templates + mkdir(dir, 'views') + pkg.dependencies['http-errors'] = '~1.7.2' + switch (options.view) { + case 'dust': + copyTemplateMulti('views', dir + '/views', '*.dust') + break + case 'ejs': + copyTemplateMulti('views', dir + '/views', '*.ejs') + break + case 'hbs': + copyTemplateMulti('views', dir + '/views', '*.hbs') + break + case 'hjs': + copyTemplateMulti('views', dir + '/views', '*.hjs') + break + case 'jade': + copyTemplateMulti('views', dir + '/views', '*.jade') + break + case 'pug': + copyTemplateMulti('views', dir + '/views', '*.pug') + break + case 'twig': + copyTemplateMulti('views', dir + '/views', '*.twig') + break + case 'vash': + copyTemplateMulti('views', dir + '/views', '*.vash') + break + } + } else { + // Copy extra public files + copyTemplate('js/index.html', path.join(dir, 'public/index.html')) + } + + // CSS Engine support + switch (options.css) { + case 'compass': + app.locals.modules.compass = 'node-compass' + app.locals.uses.push("compass({ mode: 'expanded' })") + pkg.dependencies['node-compass'] = '0.2.3' + break + case 'less': + app.locals.modules.lessMiddleware = 'less-middleware' + app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))") + pkg.dependencies['less-middleware'] = '~2.2.1' + break + case 'sass': + app.locals.modules.sassMiddleware = 'node-sass-middleware' + app.locals.uses.push("sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})") + pkg.dependencies['node-sass-middleware'] = '0.11.0' + break + case 'stylus': + app.locals.modules.stylus = 'stylus' + app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))") + pkg.dependencies.stylus = '0.54.5' + break + } + + // Index router mount + app.locals.localModules.indexRouter = './routes/index' + app.locals.mounts.push({ path: '/', code: 'indexRouter' }) + + // User router mount + app.locals.localModules.usersRouter = './routes/users' + app.locals.mounts.push({ path: '/users', code: 'usersRouter' }) + + // Template support switch (options.view) { case 'dust': - copyTemplateMulti('views', dir + '/views', '*.dust') + app.locals.modules.adaro = 'adaro' + app.locals.view = { + engine: 'dust', + render: 'adaro.dust()' + } + pkg.dependencies.adaro = '~1.0.4' break case 'ejs': - copyTemplateMulti('views', dir + '/views', '*.ejs') + app.locals.view = { engine: 'ejs' } + pkg.dependencies.ejs = '~2.6.1' break case 'hbs': - copyTemplateMulti('views', dir + '/views', '*.hbs') + app.locals.view = { engine: 'hbs' } + pkg.dependencies.hbs = '~4.0.4' break case 'hjs': - copyTemplateMulti('views', dir + '/views', '*.hjs') + app.locals.view = { engine: 'hjs' } + pkg.dependencies.hjs = '~0.0.6' break case 'jade': - copyTemplateMulti('views', dir + '/views', '*.jade') + app.locals.view = { engine: 'jade' } + pkg.dependencies.jade = '~1.11.0' break case 'pug': - copyTemplateMulti('views', dir + '/views', '*.pug') + app.locals.view = { engine: 'pug' } + pkg.dependencies.pug = '2.0.0-beta11' break case 'twig': - copyTemplateMulti('views', dir + '/views', '*.twig') + app.locals.view = { engine: 'twig' } + pkg.dependencies.twig = '~0.10.3' break case 'vash': - copyTemplateMulti('views', dir + '/views', '*.vash') + app.locals.view = { engine: 'vash' } + pkg.dependencies.vash = '~0.12.6' + break + default: + app.locals.view = false break } - } else { - // Copy extra public files - copyTemplate('js/index.html', path.join(dir, 'public/index.html')) - } - // CSS Engine support - switch (options.css) { - case 'compass': - app.locals.modules.compass = 'node-compass' - app.locals.uses.push("compass({ mode: 'expanded' })") - pkg.dependencies['node-compass'] = '0.2.3' - break - case 'less': - app.locals.modules.lessMiddleware = 'less-middleware' - app.locals.uses.push("lessMiddleware(path.join(__dirname, 'public'))") - pkg.dependencies['less-middleware'] = '~2.2.1' - break - case 'sass': - app.locals.modules.sassMiddleware = 'node-sass-middleware' - app.locals.uses.push("sassMiddleware({\n src: path.join(__dirname, 'public'),\n dest: path.join(__dirname, 'public'),\n indentedSyntax: true, // true = .sass and false = .scss\n sourceMap: true\n})") - pkg.dependencies['node-sass-middleware'] = '0.11.0' - break - case 'stylus': - app.locals.modules.stylus = 'stylus' - app.locals.uses.push("stylus.middleware(path.join(__dirname, 'public'))") - pkg.dependencies.stylus = '0.54.5' - break - } + // Static files + app.locals.uses.push("express.static(path.join(__dirname, 'public'))") - // Index router mount - app.locals.localModules.indexRouter = './routes/index' - app.locals.mounts.push({ path: '/', code: 'indexRouter' }) - - // User router mount - app.locals.localModules.usersRouter = './routes/users' - app.locals.mounts.push({ path: '/users', code: 'usersRouter' }) - - // Template support - switch (options.view) { - case 'dust': - app.locals.modules.adaro = 'adaro' - app.locals.view = { - engine: 'dust', - render: 'adaro.dust()' - } - pkg.dependencies.adaro = '~1.0.4' - break - case 'ejs': - app.locals.view = { engine: 'ejs' } - pkg.dependencies.ejs = '~2.6.1' - break - case 'hbs': - app.locals.view = { engine: 'hbs' } - pkg.dependencies.hbs = '~4.0.4' - break - case 'hjs': - app.locals.view = { engine: 'hjs' } - pkg.dependencies.hjs = '~0.0.6' - break - case 'jade': - app.locals.view = { engine: 'jade' } - pkg.dependencies.jade = '~1.11.0' - break - case 'pug': - app.locals.view = { engine: 'pug' } - pkg.dependencies.pug = '2.0.0-beta11' - break - case 'twig': - app.locals.view = { engine: 'twig' } - pkg.dependencies.twig = '~0.10.3' - break - case 'vash': - app.locals.view = { engine: 'vash' } - pkg.dependencies.vash = '~0.12.6' - break - default: - app.locals.view = false - break - } - - // Static files - app.locals.uses.push("express.static(path.join(__dirname, 'public'))") + if (options.git) { + copyTemplate('js/gitignore', path.join(dir, '.gitignore')) + } - if (options.git) { - copyTemplate('js/gitignore', path.join(dir, '.gitignore')) - } + // sort dependencies like npm(1) + pkg.dependencies = sortedObject(pkg.dependencies) - // sort dependencies like npm(1) - pkg.dependencies = sortedObject(pkg.dependencies) + // write files + write(path.join(dir, 'app.js'), app.render()) + write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n') + mkdir(dir, 'bin') + write(path.join(dir, 'bin/www'), www.render(), MODE_0755) - // write files - write(path.join(dir, 'app.js'), app.render()) - write(path.join(dir, 'package.json'), JSON.stringify(pkg, null, 2) + '\n') - mkdir(dir, 'bin') - write(path.join(dir, 'bin/www'), www.render(), MODE_0755) + var prompt = launchedFromCmd() ? '>' : '$' - var prompt = launchedFromCmd() ? '>' : '$' + if (dir !== '.') { + console.log() + console.log(' change directory:') + console.log(' %s cd %s', prompt, dir) + } - if (dir !== '.') { console.log() - console.log(' change directory:') - console.log(' %s cd %s', prompt, dir) - } - - console.log() - console.log(' install dependencies:') - console.log(' %s npm install', prompt) - console.log() - console.log(' run the app:') + console.log(' install dependencies:') + console.log(' %s npm install', prompt) + console.log() + console.log(' run the app:') - if (launchedFromCmd()) { - console.log(' %s SET DEBUG=%s:* & npm start', prompt, name) - } else { - console.log(' %s DEBUG=%s:* npm start', prompt, name) - } + if (launchedFromCmd()) { + console.log(' %s SET DEBUG=%s:* & npm start', prompt, name) + } else { + console.log(' %s DEBUG=%s:* npm start', prompt, name) + } - console.log() + console.log() - done(0) + done(0) + }) } /** diff --git a/templates/js/es6appandwww/app.js.ejs b/templates/js/es6appandwww/app.js.ejs new file mode 100644 index 00000000..b134d61c --- /dev/null +++ b/templates/js/es6appandwww/app.js.ejs @@ -0,0 +1,53 @@ +'use strict'; + +<% if (view) { -%> +const createError = require('http-errors'); +<% } -%> +const express = require('express'); +const path = require('path'); +<% Object.keys(modules).sort().forEach(function (variable) { -%> +const <%- variable %> = require('<%- modules[variable] %>'); +<% }); -%> + +<% Object.keys(localModules).sort().forEach(function (variable) { -%> +const <%- variable %> = require('<%- localModules[variable] %>'); +<% }); -%> + +const app = express(); + +<% if (view) { -%> +// view engine setup +<% if (view.render) { -%> +app.engine('<%- view.engine %>', <%- view.render %>); +<% } -%> +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', '<%- view.engine %>'); + +<% } -%> +<% uses.forEach(function (use) { -%> +app.use(<%- use %>); +<% }); -%> + +<% mounts.forEach(function (mount) { -%> +app.use(<%= mount.path %>, <%- mount.code %>); +<% }); -%> + +<% if (view) { -%> +// catch 404 and forward to error handler +app.use(function(req, res, next) { + next(createError(404)); +}); + +// error handler +app.use(function(err, req, res, next) { + // set locals, only providing error in development + res.locals.message = err.message; + res.locals.error = req.app.get('env') === 'development' ? err : {}; + + // render the error page + res.status(err.status || 500); + res.render('error'); +}); + +<% } -%> +module.exports = app; \ No newline at end of file diff --git a/templates/js/es6appandwww/www.ejs b/templates/js/es6appandwww/www.ejs new file mode 100644 index 00000000..cb90e103 --- /dev/null +++ b/templates/js/es6appandwww/www.ejs @@ -0,0 +1,90 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +const app = require('../app'); +const debug = require('debug')('<%- name %>:server'); +const http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +const port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +const server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + const port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + const bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + const addr = server.address(); + const bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} \ No newline at end of file diff --git a/templates/js/es6routes/index.js b/templates/js/es6routes/index.js new file mode 100644 index 00000000..66728c74 --- /dev/null +++ b/templates/js/es6routes/index.js @@ -0,0 +1,14 @@ +'use strict' + +const express = require('express') +const router = express.Router() + +/* GET home page. */ +router.get('/', function (req, res, next) { + try { + return res.render('index', { title: 'Express' }) + } catch (error) { + next(error) + } +}) +module.exports = router diff --git a/templates/js/es6routes/users.js b/templates/js/es6routes/users.js new file mode 100644 index 00000000..7875c2b8 --- /dev/null +++ b/templates/js/es6routes/users.js @@ -0,0 +1,15 @@ +'use strict' + +const express = require('express') +const router = express.Router() + +/* GET users listing. */ +router.get('/', function (req, res, next) { + try { + return res.send('respond with a resource') + } catch (error) { + next(error) + } +}) + +module.exports = router diff --git a/templates/js/routes/index.js b/templates/js/routes/index.js index ecca96a5..956680bd 100644 --- a/templates/js/routes/index.js +++ b/templates/js/routes/index.js @@ -1,9 +1,9 @@ -var express = require('express'); -var router = express.Router(); +var express = require('express') +var router = express.Router() /* GET home page. */ -router.get('/', function(req, res, next) { - res.render('index', { title: 'Express' }); -}); +router.get('/', function (req, res, next) { + res.render('index', { title: 'Express' }) +}) -module.exports = router; +module.exports = router diff --git a/templates/js/routes/users.js b/templates/js/routes/users.js index 623e4302..8cfe88f7 100644 --- a/templates/js/routes/users.js +++ b/templates/js/routes/users.js @@ -1,9 +1,9 @@ -var express = require('express'); -var router = express.Router(); +var express = require('express') +var router = express.Router() /* GET users listing. */ -router.get('/', function(req, res, next) { - res.send('respond with a resource'); -}); +router.get('/', function (req, res, next) { + res.send('respond with a resource') +}) -module.exports = router; +module.exports = router