I'm using the ExpressJS web framework for NodeJS.
People using ExpressJS put their environments (development, production, test...), their routes etc on the app.js
. I think that it's not a beautiful way because when you have a big application, app.js is too big!
I would like to have this directory structure:
| my-application | -- app.js | -- config/ | -- environment.js | -- routes.js
Here's my code:
app.js
var express = require('express'); var app = module.exports = express.createServer(); require('./config/environment.js')(app, express); require('./config/routes.js')(app); app.listen(3000);
config/environment.js
module.exports = function(app, express){ app.configure(function() { app.use(express.logger()); }); app.configure('development', function() { app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); }); app.configure('production', function() { app.use(express.errorHandler()); }); };
config/routes.js
module.exports = function(app) { app.get('/', function(req, res) { res.send('Hello world !'); }); };
My code works well and I think that the structure of the directories is beautiful. However, the code had to be adapted and I'm not sure that it's good/beautiful.
Is it better to use my structure of directories and adapt the code or simply use one file (app.js)?
Thanks for your advices!
js, Import express with require keyword and create an app by calling the express() function provided by the express framework. Set the port for our local application, 3000 is the default but you can choose any according to the availability of ports.
Express has not been updated for years, and its next version has been in alpha for 6 years. People may think it is not updated because the API is stable and does not need change. The reality is: Express does not know how to handle async/await .
Middleware frameworks, like Express. js, are suitable for small and medium projects. If you are going to develop a large project that will be supported by a large team of developers, Express. js is not the best choice.
Since ExpressJS doesn't follow MVC, there's no proper structure which makes the application inefficient and less optimized. NestJS becomes a better choice for developers as it is clearly based on an architecture with components like modules, controllers, and providers.
OK, it's been a while and this is a popular question, so I've gone ahead and created a scaffolding github repository with JavaScript code and a long README about how I like to structure a medium-sized express.js application.
focusaurus/express_code_structure is the repo with the latest code for this. Pull requests welcome.
Here's a snapshot of the README since stackoverflow doesn't like just-a-link answers. I'll make some updates as this is a new project that I'll continue updating, but ultimately the github repo will be the up-to-date place for this information.
This project is an example of how to organize a medium-sized express.js web application.
Current to at least express v4.14 December 2016
Web applications are not all the same, and there's not, in my opinion, a single code structure that should be applied to all express.js applications.
If your application is small, you don't need such a deep directory structure as exemplified here. Just keep it simple and stick a handful of .js
files in the root of your repository and you're done. Voilà.
If your application is huge, at some point you need to break it up into distinct npm packages. In general the node.js approach seems to favor many small packages, at least for libraries, and you should build your application up by using several npm packages as that starts to make sense and justify the overhead. So as your application grows and some portion of the code becomes clearly reusable outside of your application or is a clear subsystem, move it to it's own git repository and make it into a standalone npm package.
So the focus of this project is to illustrate a workable structure for a medium-sized application.
There are many approaches to building a web application, such as
Each of these fits nicely into a different directory structure. For the purposes of this example, it's just scaffolding and not a fully working app, but I'm assuming the following key architecture points:
It will be a theme throughout this project that many of the ideas embodied in Ruby on Rails and the "Convention over Configuration" decisions they have adopted, though widely accepted and used, are not actually very helpful and sometimes are the opposite of what this repository recommends.
My main point here is that there are underlying principles to organizing code, and based on those principles, the Ruby on Rails conventions make sense (mostly) for the Ruby on Rails community. However, just thoughtlessly aping those conventions misses the point. Once you grok the basic principles, ALL of your projects will be well-organized and clear: shell scripts, games, mobile apps, enterprise projects, even your home directory.
For the Rails community, they want to be able to have a single Rails developer switch from app to app to app and be familiar and comfortable with it each time. This makes great sense if you are 37 signals or Pivotal Labs, and has benefits. In the server-side JavaScript world, the overall ethos is just way more wild west anything goes and we don't really have a problem with that. That's how we roll. We're used to it. Even within express.js, it's a close kin of Sinatra, not Rails, and taking conventions from Rails is usually not helping anything. I'd even say Principles over Convention over Configuration.
app/node_modules
directory and have package.json
files in the proto-module directories to facilitate that transition and act as a reminder.app
directory so you can cd
there are run find/grep/xargs/ag/ack/etc and not be distracted by third party matcheskebab-case
even though the variable name for that in JavaScript must be camelCase
because -
is a minus sign in JavaScript.kebab-case
transformed to camelCase
app/views
, app/controllers
, app/models
, etcroutes.rb
file is handy if you want an overview of all routes in the app, but when actually building features and fixing bugs, you only care about the routes relevant to the piece you are changing.app/users
because there's not a rat's nest of coupled business logic all over the place polluting the purity of the user code base.app/server.js:1
and you can see everything it loads and executes by following the code.magicRESTRouter.route(somecontroller, {except: 'POST'})
is a big win for you over 3 basic app.get
, app.put
, app.del
, calls, you're probably building a monolithic app that is too big to effectively work on. Get fancy for BIG wins, not for converting 3 simple lines to 1 complex line.Use lower-kebab-case filenames
Don't use app.configure
. It's almost entirely useless and you just don't need it. It is in lots of boilerplate due to mindless copypasta.
app.use
for your entire application if you really only need that middleware for 2 routes (I'm looking at you, body-parser
)server.js
and it will be clear how they are ordered. For a medium-sized application, breaking things out into separate routes modules is nice, but it does introduce peril of out-of-order middlewareThere are many approaches outlined and discussed at length by the community in the great gist Better local require() paths for Node.js. I may soon decide to prefer either "just deal with lots of ../../../.." or use the requireFrom modlue. However, at the moment, I've been using the symlink trick detailed below.
So one way to avoid intra-project requires with annoying relative paths like require("../../../config")
is to use the following trick:
.gitignore
filevar config = require("app/config");
var DealModel = require("app/deals/deal-model")
;Generally code modules and classes to expect only a basic JavaScript options
object passed in. Only app/server.js
should load the app/config.js
module. From there it can synthesize small options
objects to configure subsystems as needed, but coupling every subsystem to a big global config module full of extra information is bad coupling.
Try to centralize creation of DB connections and pass those into subsystems as opposed to passing connection parameters and having subsystems make outgoing connections themselves.
This is another enticing but terrible idea carried over from Rails. There should be exactly 1 place in your app, app/config.js
that looks at the NODE_ENV
environment variable. Everything else should take an explicit option as a class constructor argument or module configuration parameter.
If the email module has an option as to how to deliver emails (SMTP, log to stdout, put in queue etc), it should take an option like {deliver: 'stdout'}
but it should absolutely not check NODE_ENV
.
I now keep my test files in the same directory as their corresponding code and use filename extension naming conventions to distinguish tests from production code.
foo.js
has the module "foo"'s codefoo.tape.js
has the node-based tests for foo and lives in the same dirfoo.btape.js
can be used for tests that need to execute in a browser environmentI use filesystem globs and the find . -name '*.tape.js'
command to get access to all my tests as necessary.
.js
module fileThis project's scope is mostly about where files and directories go, and I don't want to add much other scope, but I'll just mention that I organize my code into 3 distinct sections.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With