Is it possible to seamlessly transition an express app to meteor?

Currently working on migrating an app from node.js with express framework to meteor. Attempting to reverse engineer the process using a method similar to https://github.com/onmodulus/demeteorizer

Answer №1

While it's not entirely automatic, there are several clever techniques you can string together to achieve a near-automatic solution.

I've personally navigated through this process and compiled all of my best tricks for you here.

Let's kick off with your express app main .js file. Here's the snippet you need to add at the beginning:

/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;
    } 
};

This code simply defines the necessary app functions and stores the defined routes in an object used later on to set those routes with iron-router. This ensures that details like the below are captured in routes:

/server/main.js:

app.get('/show', function(req, res) {
    res.render('mytemplate');
});

That's the key trick. The rest is just hard work.

In line with good meteor coding principles, we'll encapsulate all route rendering calls within a fiber to synchronize them with other processes run by the meteor server. To accomplish this, we define a wrapper function called waiter that we can repeatedly use to wrap the route functions. While doing so, we will also adapt the connect request and response received from iron-routes on the meteor server into the res and req objects expected by express. Bear in mind: this isn't comprehensive; it outlines the signatures I chose to use from these objects.

/server/main.js:

/** create a synchronous version for meteor */
waiter = function(foo, req, res) {
    var waiter_aux = Meteor._wrapAsync(function(foo, req, res, callback) {

        // Various adaptations for res
        res.set = function(header, value) {
            res.setHeader(header, value);
        };

        res.send = function(codeorhtml, html) {
            if (html) {
                res.statusCode = codeorhtml;
            } else {
                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;

        foo(req, res); // Further extensions needed for these objects
    });

    return waiter_aux(foo, req, res);
};

Now comes the real test: setting up routes for each specified express route. To do this, we leverage iron-router. The following code loops through every defined route (captured by our redefined app functions and stored in routes), wrapping them in fibers using our waiter function which handles the translation between this.request/this.response and the req and res objects expected by express applications.

/routes.js:

if (Meteor.isServer) {
    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 represent the crucial steps I took to address your query. Though some finer points may have been left out, this outline should provide useful insights.


Post-Spacebars update (I don't recall the specific Meteor version):

To execute this successfully, you now need to introduce handlebars-server:

meteor add cmather:handlebars-server

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is there a way to send a file with React? Or are there similar methods like `npm unload` for Express?

Is there a way to send files using React similar to express' sendFile method? For example, in express, sending an .exe file would prompt a download, a PDF file would be displayed in the browser, and an image file would also be displayed. I'm curi ...

Cross-Origin Resource Sharing (CORS): The preflight request response does not satisfy the access control check

I've been facing an issue with a simple POST method to my API through the browser. The request fails, but when I try the same on Postman, it works fine. The response includes a JSON string and two cookies. In an attempt to resolve this, I set the hea ...

Meteor, enhanced with the dynamic Iron Router module and integrated

I am working on a project using Meteor (Meteor.com) and I want to incorporate iron-router for the page routing along with the pre-existing accounts-ui package for login functionality. Previously, my {{loginButtons}} functioned properly, but ever since I i ...

Node application running in Docker cannot establish connection with the Postgres database also running in Docker

I've experimented with various solutions, but none of them seem to work for me. Here's what I did: I set up a nodejs container and a postgres docker container. I used docker compose to configure both and a Dockerfile to build the nodejs/typescri ...

Why won't my test in WebdriverJS and Jasmine redirect the browser to the intended URL?

Currently, I am executing a test suite with the following setup: nodejs selenium-webdriver jasmine-node (utilizing jasmine 1.3) Upon running the spec provided below, the browser window initializes but fails to redirect to the specified URL - instead, it ...

Using NodeJS and Express may lead to a concurrency problem when trying to access the res.locals object

My web application is built using NodeJS, Express, and Jade 4.13.4. In the index.js file, I have defined a route as shown below: index.js var express = require('express') , app = express() , companyroutes = require('./routes/company&ap ...

Encapsulate asynchronous function to generate a promise (using bluebird)

I am looking to wrap some synchronous functions in Bluebird promises in order to combine them with other asynchronous methods. After following the advice from another question on this topic, I have created two methods wrapped in promises: var Promise = r ...

Unable to deploy Docker image with gcloud app deploy command

I am encountering an issue while attempting to deploy my Node.js application on Google Cloud Platform (GCP) using the Google Cloud SDK. Despite being a beginner, I have been relying on the basic deploy command. gcloud app deploy Everything was running sm ...

Guidelines for implementing an onSubmit function using Material-UI

Hey there, I'm relatively new to node.js / react / material-ui. Following a tutorial to build a website has been going smoothly so far. I decided to spice things up by adding material-ui for some sleek components (which weren't covered in the tut ...

AWS EC2 port has been successfully opened, however access remains unattainable

My TCP port 3000 is enabled, as indicated in the EC2 security settings. However, I am unable to connect to my server through telnet on that port and receive the error message Could not open connection to the host, on port 3000: Connect failed. The server ...

Node.js CallbackHandler: Simplifying event handling in JavaScript applications

I implemented the following function in a .js file to handle an asynchronous network connection: function requestWatsonDiscovery(queryString) { console.log('Query =', queryString); if (typeof queryString !== 'undefined') { ...

What steps should I take to resolve the 'invalid mime type' issue while transmitting an image as a binary string to Stability AI via Express?

Currently, I am facing an issue while attempting to utilize the image-to-image API provided by stabilityAI. The task at hand involves sending an image as a binary string through my express server to the stability AI API. However, when I make the POST reque ...

com.parse.ParseRequest$ParseRequestException: incorrect JSON response encountered during transition to Heroku for Parse server

I recently transitioned my Parse server from Heroku and my database from parse.com to MangoLab. However, I am encountering an error when making requests from my Android app. com.parse.ParseRequest$ParseRequestException: bad json response Here is the code ...

listening for new messages on discord using a loop in discord.js

My Discord.js bot is experiencing an issue where the callback function for the "message" event is not triggering inside a loop in my code, despite working correctly everywhere else. I've tried using console.log statements for debugging but haven' ...

Express is throwing a TypeError because it is unable to access the property 'app', which is undefined

On my nodejs server running the express framework, I have been encountering a random error when making requests. The error occurs unpredictably, usually appearing on the first request and not on subsequent ones. It's challenging for me to identify the ...

The data in my MySQL table is not appearing on an Angular Material table when using Node.js

HTML file content <table mat-table [dataSource]="dataSource" class="mat-elevation-z8"> <ng-container matColumnDef="id"> <th mat-header-cell *matHeaderCellDef> No. </th> <td mat-cell *matCellDef="let element"> {{ele ...

Error: The function "parse" is not defined

After installing the Font Awesome dependencies for my app and attempting to run npm start to test it, I encountered a troublesome error that has proven to be quite challenging to solve. $ npm start > <a href="/cdn-cgi/l/email-protection" class="__cf ...

Steps for transferring data from a POST response to the client in NodeJS/ExpressJS

I am currently in the process of setting up an EasyPost API and I need to save some data that is included in a response from a POST route. My goal is to send this data directly to the client for storage, but I am struggling to determine where or how to do ...

Incorporate relationships while inserting data using Sequelize

vegetable.js ... var Vegetable = sequelize.define('Vegetable', { recipeId: { allowNull: false, ... }, name: { ... }, }); Vegetable.association = models => { Vegetable.belongsTo(models.Recipe); }; ... recipe.js ... var Recipe = sequeliz ...

What techniques can I utilize to ensure Azure function generates JSON specifically for web browsers?

I have a functioning Azure function with the following code: module.exports = function(context, req) { // this is the complete source code, believe it or not context.done(null, {favoriteNumber: 3}); }; When I utilize a tool like Postman to access ...