Express is one of the most flexible web hosting libraries I have used in my career. I love how simple it can be, and how it allows you to grow your system as needed. One of the areas that has continued to bother me in my own code, though, is my lack of ability to cleanly separate different parts of my Express app without duplicating the entire Express configuration and using sub-domains / multiple dns entries.
In a recent email conversation, however, a friend pointed out a modularized approach they are taking with Express apps. The code they showed got me thinking about Rails “engines” and other sub-application mounting techniques I’ve seen.
And that got me curious – did Express support the ability to mount other Express apps, as a sort of host / sub-app scenario?
Mounting Express Apps Into An Express App
Previously, I have separated what may have been a /admin route into a completely separate sub-domain, like “http://admin.example.com”. This worked well for the scenario described in that post, but I wanted something else in this case. While I do see value in moving /admin out to a separate sub-domain, still, I also see a lot of value in separating /admin into it’s own project folder and still mounting it as /admin in the main Express app.
I was looking for something like an “engine” or “sub-app” that I could use. I wanted a way to keep my /api code separate from the end-user web app and html, for example.
What I found was how the mechanism that allows me to .use() a router or sub-router, also works on the Express application instance! That means I can create new instances of the Express object, and .use it in another Express object just like a router or other middleware.
This code may be well known to other people, but it was a mind-blown experience for me, to see it running.
Potential Benefits For Sub-Applications
I see a lot of potential for application structure that uses sub-apps like this. Ultimately, sub-applications provide flexibility and allow me to keep my code clean. But I see other benefits, such as keeping code for various routes completely separate.
My previous use of “admin.example.com” could easily turn into “example.com/admin” while still providing the same level of protection in the code. Additionally, the “/api” route could be handled by code that doesn’t need to know anything about view rendering.
I’ve also had large complaints about all of the garbage that the general Express app.js file contains, in the past. There are far too many concerns stuffed into this file, in most applications, because we don’t know where else to put the code.
By splitting the Express application into sub-apps, the app.js file can have it’s responsibilities split as well. Each sub-app will configure what it needs, while allowing the Express host app to configure the defaults or root-level settings.
This could also promote re-use of application chunks by packaging the sub-app as an npm module.
There are other potential benefits as well, and I think there are still benefits to using a separate sub-domain. Sub-apps aren’t a golden-hammer-silver-bullet, but I think they offer additional value in what I’m looking for at this point.
A Demo Express Sub-Application
Given my new toy, I did what I usually do – I ran with it to a fair extreme to see where it would fall apart. The result of this experiment is a simple example project on Github to demonstrate Express ability to host sub-apps within an Express app.
This repository is a demonstration Express’ to take what would have been cluttered code from multiple route paths, a giant app.js file (and worse), separate these parts into their own application instance, and bring them back together in a single application host.
The result is a clean application structure, in my mind, with several sub-apps mounted into a primary host app.
Demo Code Structure
This demo project is split up into multiple Express application instances, each of which handles a specific portion of the over-all web application.
The primary application is:
- host: The root express app and the actual web server into which the other apps are mounted
The sub-application instances include:
- api: Mounted at /api, handles the JSON based API access for the app
- web: Mounted at /, handles the core web pages for browser based usage
- errors: Mounted in the root express app, handles root level 404 and route / middleware errors
You’ll note in each of these projects, that various parts of the default Express app (as generated by the Express-Generator project) have been removed.
For example, the api project does not need to render any Jade views, so the view engine registration and views folders have been removed from this project. Similarly, none of the sub-applications need to have actual web server code from the bin/www file – only the host application needs this.
On Being An “extreme” Example App
I call this demo code an “extreme example” because I have purposely taken the separation out to the edge of what I might consider useful. Taking this to an extreme allows us to see the bounds of where this might be useful.
It is still possible to take this separation of apps further, creating more sub-applications to split further responsibilities apart. For example, you could split the “development” vs “production” error handlers into separate app instances, and only mount the one you need.
However, this might really jump the bounds of usefulness… depending on your circumstances, of course.
Attempting Use In A Production App
It’s all good to do some academic research and build a sample project like this. But now I’m wondering what this will end up like in a real application that has to be supported, long term.
So, I’ve taken a dive off the deep-end and restructured one of my existing applications for a client, in this manner. I took code that was previously set up with a single Express app in the “www” folder:
In each of the “api”, “web” and “host” folders, you’ll find a standard app.js file like Express typically generates. The various folders don’t have the same structure as each other beyond that, however.
Like the demo code in the github repo, the api app does not require any Jade views so I took out the views folder and did not register a template engine w/ the Express app instance.
There are other differences as well, some of which you can see in the folder structure, while others live in the code.
Try The Demo Code, Leave Some Feedback
This is still pretty new to me, at this point, but I’m moving forward with it fairly quickly in the project I’ve shown above. But I know I’m probably going to take this to an extreme that is unmaintainable, and probably run into other problems that other people have faced when trying this.
So, I’d love to hear from you – what you think of this approach, what problems you’ve run into when trying it, etc.
Check out the Express Sub-App Demo repo, and leave some feedback in the issues list. Help me improve the code and prevent the problems that you’ve seen with this approach!