Definitely not automatically, but there are a bunch of tricks you can chain together to almost get it automatically.
I've been through just that and here are all of my tricks for this.
Let's start with your express app main .js file. This one you need to add the following at the top:
/server/main.js
:
routes = {};
var app = {
get: function(route, foo) {
// routes.get[route] = foo;
routes[route] = foo;
},
all: function(route, foo) {
// routes.all[route] = foo;
routes[route] = foo;
}
};
All this does is to define the app
functions you need, and record the defined routes in an object, which we will later use to define those routes using iron-router
. So this makes sure that things like the following get recorded in routes
:
/server/main.js
:
app.get('/show', function(req, res) {
res.render('mytemplate');
});
That's really the main trick. From here on its just labor.
In good meteor style, we will wrap all route rendering calls into a fiber, to make them synchronous like everything else on the meteor server. For that, we define a wrapping function waiter
that we can reuse over and over again to wrap the route functions. And while we are add it, we will massage the connect request and response that we will get from the iron-routes on the meteor server into the res
and req
objects express would like to see. Mind you: this is not complete by any stretch. It's just the signatures I wanted to use from these objects.
/server/main.js
:
/** create an sync version for meteor */
waiter = function(foo, req, res) {
var waiter_aux = Meteor._wrapAsync(function(foo, req, res, callback) {
res.set = function(header, value) {
res.setHeader(header, value);
};
res.send = function(codeorhtml, html) {
if (html) {
// two arguments provided, treat as described
res.statusCode = codeorhtml;
} else {
// no code, just html
html = codeorhtml;
}
callback(null, html);
};
res.render = function(name, data, callback) {
callback = callback || function(err, html) {
res.send(html);
};
var html = Handlebars.templates[name](data);
callback(null, html);
};
res.json = function(object) {
res.send(JSON.stringify(object));
}
res.redirect = function(URL) {
res.writeHead(302, {
'Location': URL
});
res.end();
};
req.header = function(x) {
return this.header[x];
};
TemplatesObject = Handlebars.templates;
// these objects need to be extended further
foo(req, res);
});
return waiter_aux(foo, req, res);
};
Finally, the real deal: creating routes for each specified express route. For this we will use iron-router. The following code will go through each defined route (caught by our redefined app
functions and stored in routes
), and wrap it in a fiber using our waiter
, which will also take care of translating between this.request
/this.response
and the req
and res
objects express apps assume.
/routes.js
:
if (Meteor.isServer) {
// create routes for all the app.get's and app.all's in bibbase.js
// (server)
console.log("setting routes:", routes);
_.each(routes, function(foo, route) {
Router.map(function () {
this.route(route, {
path: route,
where: 'server',
action: function() {
this.request.params = this.params;
var html = waiter(foo, this.request, this.response);
if (!this.response.statusCode) {
this.response.statusCode = 200;
}
if (!this.response.getHeader('Content-Type')) {
this.response
.setHeader('Content-Type', 'text/html');
}
this.response.end(html);
}
});
});
});
}
These are the most essential things I've done to accomplish what you are asking about. I'm sure I've missed a few details here, but this should give you an idea.
Update for post-Spacebars (I forget which version of Meteor that was):
In order to make this work, you now need to add handlebars-server:
meteor add cmather:handlebars-server