Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there an easy way to convert an express app to meteor? [closed]

I am trying to convert a node.js with express framework app to meteor. Essentially doing the reverse way of https://github.com/onmodulus/demeteorizer

like image 670
user3529515 Avatar asked Apr 13 '14 17:04

user3529515


1 Answers

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
like image 183
Christian Fritz Avatar answered Nov 15 '22 03:11

Christian Fritz