Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ES module option. #316

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ This generator can also be further configured with the following command line fl
--no-view use static html instead of view engine
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git add .gitignore
--es6 generate ES6 code and module-type project (requires Node 14.x or higher)
-f, --force force on non-empty directory
-h, --help output usage information

Expand Down
25 changes: 18 additions & 7 deletions bin/express-cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ var MODE_0666 = parseInt('0666', 8)
var MODE_0755 = parseInt('0755', 8)
var TEMPLATE_DIR = path.join(__dirname, '..', 'templates')
var VERSION = require('../package').version
var MIN_ES6_VERSION = 14

// parse args
var unknown = []
Expand All @@ -26,7 +27,7 @@ var args = parseArgs(process.argv.slice(2), {
H: 'hogan',
v: 'view'
},
boolean: ['ejs', 'force', 'git', 'hbs', 'help', 'hogan', 'pug', 'version'],
boolean: ['ejs', 'es6', 'force', 'git', 'hbs', 'help', 'hogan', 'pug', 'version'],
default: { css: true, view: true },
string: ['css', 'view'],
unknown: function (s) {
Expand Down Expand Up @@ -95,17 +96,20 @@ function createApplication (name, dir, options, done) {
version: '0.0.0',
private: true,
scripts: {
start: 'node ./bin/www'
start: options.es6 ? 'node ./bin/www.mjs' : 'node ./bin/www'
},
dependencies: {
debug: '~2.6.9',
express: '~4.17.1'
}
}
if (options.es6) {
pkg.type = 'module'
}

// JavaScript
var app = loadTemplate('js/app.js')
var www = loadTemplate('js/www')
var app = loadTemplate(options.es6 ? 'mjs/app.js' : 'js/app.js')
var www = loadTemplate(options.es6 ? 'mjs/www' : 'js/www')

// App name
www.locals.name = name
Expand Down Expand Up @@ -160,7 +164,9 @@ function createApplication (name, dir, options, done) {

// copy route templates
mkdir(dir, 'routes')
copyTemplateMulti('js/routes', dir + '/routes', '*.js')
copyTemplateMulti(
options.es6 ? 'mjs/routes' : 'js/routes',
dir + '/routes', options.es6 ? '*.mjs' : '*.js')

if (options.view) {
// Copy view templates
Expand Down Expand Up @@ -283,10 +289,10 @@ function createApplication (name, dir, options, done) {
pkg.dependencies = sortedObject(pkg.dependencies)

// write files
write(path.join(dir, 'app.js'), app.render())
write(path.join(dir, options.es6 ? 'app.mjs' : '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(path.join(dir, options.es6 ? 'bin/www.mjs' : 'bin/www'), www.render(), MODE_0755)

var prompt = launchedFromCmd() ? '>' : '$'

Expand Down Expand Up @@ -433,6 +439,10 @@ function main (options, done) {
usage()
error('option `-v, --view <engine>\' argument missing')
done(1)
} else if (options.es6 && process.versions.node.split('.')[0] < MIN_ES6_VERSION) {
usage()
error('option `--es6\' requires Node version ' + MIN_ES6_VERSION + '.x or higher')
done(1)
} else {
// Path
var destinationPath = options._[0] || '.'
Expand Down Expand Up @@ -521,6 +531,7 @@ function usage () {
console.log(' --no-view use static html instead of view engine')
console.log(' -c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)')
console.log(' --git add .gitignore')
console.log(' --es6 generate ES6 code and module-type project (requires Node 14.x or higher)')
console.log(' -f, --force force on non-empty directory')
console.log(' --version output the version number')
console.log(' -h, --help output usage information')
Expand Down
54 changes: 54 additions & 0 deletions templates/mjs/app.js.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<% if (view) { -%>
import createError from 'http-errors';
<% } -%>
import express from 'express';
drjeffjackson marked this conversation as resolved.
Show resolved Hide resolved
import path from 'path';
import { fileURLToPath } from 'url';
<% Object.keys(modules).sort().forEach(function (variable) { -%>
import <%- variable %> from '<%- modules[variable] %>';
<% }); -%>

<% Object.keys(localModules).sort().forEach(function (variable) { -%>
import <%- variable %> from '<%- localModules[variable] %>.mjs';
<% }); -%>

const __dirname = path.dirname(fileURLToPath(import.meta.url));

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((req, res, next) => {
next(createError(404));
});

// error handler
app.use((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');
});

<% } -%>
export default app;
9 changes: 9 additions & 0 deletions templates/mjs/routes/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express';
const router = express.Router();

/* GET home page. */
router.get('/', (req, res, next) => {
res.render('index', { title: 'Express' });
});

export default router;
9 changes: 9 additions & 0 deletions templates/mjs/routes/users.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import express from 'express';
const router = express.Router();

/* GET users listing. */
router.get('/', (req, res, next) => {
res.send('respond with a resource');
});

export default router;
91 changes: 91 additions & 0 deletions templates/mjs/www.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env node

/**
* Module dependencies.
*/

import app from '../app.mjs';
import http from 'http';
drjeffjackson marked this conversation as resolved.
Show resolved Hide resolved
import debugFunction from 'debug';
const debug = debugFunction('<%- name %>:server');

/**
* 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);
}
Loading