Search code examples
node.jsexpressjsdomappfog

Error with Express on AppFog but not in local


I get an error when I host my app on AppFog. Line 50, when I call JSDOM... The issue doesn't appear in local, I don't understand why it doesn't work in remote...

My code (works in local):

exports.index = function(req, res) {
    Creation.findAll({where: "state = 1",order: 'id DESC', limit: 2}).success( function(creations) {
        Post.findAll({where: "state = 1",order: 'id DESC', limit: 2}).success(function(posts){
            async.map(posts, function(postEntity, callback){
                jsdom.env( // PROBLEM HERE
                    postEntity.content,
                    ["http://code.jquery.com/jquery.js"],
                    function(errors, window) {
                        if(errors) return callback(errors);
                        postEntity.content = window.$("p").text();
                        callback(null, postEntity);
                    }
                );
            }, function(err, transformedPosts){
                if(err) return callback(err);
                res.render('index', {
                    creations: creations,
                    posts: transformedPosts,
                    title: "Anthony Cluse | Portfolio"
                });
            });
        });
    });
};

My error (on AppFog - I sent a request to the support):

TypeError: Cannot read property 'implementation' of undefined
at exports.env.exports.jsdom.env.processHTML (/mnt/var/vcap.local/dea/apps/anthonycluse-1-  0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/jsdom/lib/jsdom.js:178:59)
at Object.exports.env.exports.jsdom.env (/mnt/var/vcap.local/dea/apps/anthonycluse-1-   0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/jsdom/lib/jsdom.js:269:5)
at exports.index.Creation.findAll.success.Post.findAll.success.async.map.res.render.creations (/mnt/var/vcap.local/dea/apps/anthonycluse-1- 0c3b7373ee2a0a1334d2ea77a9bf22c8/app/routes/index.js:50:23)
at _asyncMap (/mnt/var/vcap.local/dea/apps/anthonycluse-1-0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:222:13)
at async.each (/mnt/var/vcap.local/dea/apps/anthonycluse-1-0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:99:13)
at Array.forEach (native)
at _each (/mnt/var/vcap.local/dea/apps/anthonycluse-1-0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:32:24)
at async.each (/mnt/var/vcap.local/dea/apps/anthonycluse-1-0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:98:9)
at _asyncMap (/mnt/var/vcap.local/dea/apps/anthonycluse-1-0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:221:9)
at Object.doParallel [as map] (/mnt/var/vcap.local/dea/apps/anthonycluse-1- 0c3b7373ee2a0a1334d2ea77a9bf22c8/app/node_modules/async/lib/async.js:199:23)

Logs on AppFog:

====> /logs/staging.log <====

# Logfile created on 2013-02-22 23:41:12 +0000 by logger.rb/25413
Skipping npm support: npm-shrinkwrap.json is not provided

====> /logs/stdout.log <====

Express server listening on port 56643
Executing: CREATE TABLE IF NOT EXISTS `Posts` (`slug` VARCHAR(255), `title` VARCHAR(255), `thumbnail` VARCHAR(255), `content` TEXT, `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Creations` (`slug` VARCHAR(255), `screenshot` VARCHAR(255), `title` VARCHAR(255), `subtitle` VARCHAR(255), `url` VARCHAR(255), `content` TEXT, `webdesigner` VARCHAR(255), `developper` VARCHAR(255), `integrator` VARCHAR(255), `designer` VARCHAR(255), `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Posts` (`slug` VARCHAR(255), `title` VARCHAR(255), `thumbnail` VARCHAR(255), `content` TEXT, `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Creations` (`slug` VARCHAR(255), `screenshot` VARCHAR(255), `title` VARCHAR(255), `subtitle` VARCHAR(255), `url` VARCHAR(255), `content` TEXT, `webdesigner` VARCHAR(255), `developper` VARCHAR(255), `integrator` VARCHAR(255), `designer` VARCHAR(255), `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: SELECT * FROM `Creations` WHERE state = 1 ORDER BY id DESC LIMIT 2;
Executing: SELECT * FROM `Posts` WHERE state = 1 ORDER BY id DESC LIMIT 2;
{ __options: 
   { timestamps: true,
     instanceMethods: {},
     classMethods: {},
     validate: {},
     freezeTableName: false,
     underscored: false,
     syncOnAssociation: true,
     paranoid: false,
     omitNull: false,
     hasPrimaryKeys: false },
  hasPrimaryKeys: false,
  selectedValues: 
   { slug: 'my-first-post',
     title: 'my first post',
     thumbnail: 'http://i.pcworld.fr/1151321-espace-sfr.jpg',
     content: '<p>\r\nun content pour le premier post\r\n</p>\r\n<img src="http://i.pcworld.fr/1151321-espace-sfr.jpg">\r\n<p>et la suite !!!</p>',
     state: 1,
     id: 1,
     createdAt: Thu Feb 21 2013 21:45:58 GMT+0000 (UTC),
     updatedAt: Thu Feb 21 2013 21:46:00 GMT+0000 (UTC) },
  slug: 'my-first-post',
  title: 'my first post',
  thumbnail: 'http://i.pcworld.fr/1151321-espace-sfr.jpg',
  content: '<p>\r\nun content pour le premier post\r\n</p>\r\n<img src="http://i.pcworld.fr/1151321-espace-sfr.jpg">\r\n<p>et la suite !!!</p>',
  state: 1,
  id: 1,
  createdAt: Thu Feb 21 2013 21:45:58 GMT+0000 (UTC),
  updatedAt: Thu Feb 21 2013 21:46:00 GMT+0000 (UTC),
  isNewRecord: false }

====> /logs/staging.log <====

# Logfile created on 2013-02-22 23:41:12 +0000 by logger.rb/25413
Skipping npm support: npm-shrinkwrap.json is not provided

====> /logs/stdout.log <====

Express server listening on port 48140
Executing: CREATE TABLE IF NOT EXISTS `Posts` (`slug` VARCHAR(255), `title` VARCHAR(255), `thumbnail` VARCHAR(255), `content` TEXT, `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Creations` (`slug` VARCHAR(255), `screenshot` VARCHAR(255), `title` VARCHAR(255), `subtitle` VARCHAR(255), `url` VARCHAR(255), `content` TEXT, `webdesigner` VARCHAR(255), `developper` VARCHAR(255), `integrator` VARCHAR(255), `designer` VARCHAR(255), `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Posts` (`slug` VARCHAR(255), `title` VARCHAR(255), `thumbnail` VARCHAR(255), `content` TEXT, `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;
Executing: CREATE TABLE IF NOT EXISTS `Creations` (`slug` VARCHAR(255), `screenshot` VARCHAR(255), `title` VARCHAR(255), `subtitle` VARCHAR(255), `url` VARCHAR(255), `content` TEXT, `webdesigner` VARCHAR(255), `developper` VARCHAR(255), `integrator` VARCHAR(255), `designer` VARCHAR(255), `state` INTEGER, `id` INTEGER NOT NULL auto_increment , `createdAt` DATETIME NOT NULL, `updatedAt` DATETIME NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB;

Edit with Cheerio:

var cheerio = require('cheerio'), $;

exports.index = function(req, res) {
    Creation.findAll({where: "state = 1",order: 'id DESC', limit: 2}).success( function(creations) {
        Post.findAll({where: "state = 1",order: 'id DESC', limit: 2}).success(function(posts){
            async.map(posts, function(postEntity, callback){
                $ = cheerio.load(postEntity.content);
                postEntity.content = $("p").text();
                /*
                jsdom.env(
                    postEntity.content,
                    ["http://code.jquery.com/jquery.js"],
                    function(errors, window) {
                        //deal with errors
                        if(errors) return callback(errors);
                        postEntity.content = window.$("p").text();
                        callback(null, postEntity);
                    }
                );
                */
            }, function(err, transformedPosts){
                if(err) return callback(err);
                res.render('index', {
                    creations: creations,
                    posts: transformedPosts,
                    title: "Anthony Cluse | Portfolio"
                });
            });
        });
    });
};

Solution

  • It appears jsdom relies on a native library that does not work on CloudFoundry, same thing AppFog uses.

    see this jsdom isssue https://github.com/tmpvar/jsdom/issues/436

    workaround would be to use something like cheerio (https://github.com/MatthewMueller/cheerio)

    Here's an example from the home page:

    var cheerio = require('cheerio');
    var $ = cheerio.load('<h2 class = "title">Hello world</h2>');
    
    $('h2.title').text('Hello there!');
    $('h2').addClass('welcome');