Meteor SSR "Error: Can't render undefined" - node.js

I am trying to get server-side rendering using IronRouter and Meteor-SSR in a basic Meteor app. When I load /home in the browser I get the following error:
Error: Can't render undefined
at checkRenderContent (packages/blaze.js:702:11)
at contentAsView (packages/blaze.js:724:3)
at Blaze.toHTML (packages/blaze.js:851:40)
at Object.SSR.render (packages/meteorhacks_ssr.js:208:10)
at [object Object].Router.route.where (main.js:9:20)
at boundNext (packages/iron_middleware-stack.js:408:31)
at runWithEnvironment (packages/meteor.js:1176:24)
at packages/meteor.js:1189:14
at [object Object].urlencodedParser (/Users/roger/.meteor/packages/iron_router/.1.1.1.1q7cd8x++os+web.browser+web.cordova/npm/node_modules1/body-parser/lib/types/urlencoded.js:84:40)
at packages/iron_router.js:886:36
Here's the code for the app:
// main.js
if (Meteor.isServer) {
Router.route('/home', function() {
let html = SSR.render('home');
this.response.end(html);
}, {where: 'server'});
}
if (Meteor.isClient) {
Router.route('/home', function() {
this.render("home")
});
}
Here's main.html:
<head>
<title>SSR Test</title>
</head>
<body>
</body>
<template name="home">
Home
</template>

This happens because your home template is not defined on server. To use SSR package, you need to compile the template in your server with SSR.compileTemplate first, only then you could render it with SSR.render. This is a simple example for you:
if (Meteor.isServer) {
const template = 'Hello {{username}}, <br> Now time is: {{time}}';
SSR.compileTemplate('hello', template);
Router.route('/home', function() {
const html = SSR.render('hello', {
username: 'foo',
time: new Date(),
});
this.response.end(html);
}, {where: 'server'});
}
There is also a better to compile template from static file on server which could be found here

Related

How to return a 404 Not found page in an Express App?

I have an express app, in which I have the following code:
app.get('*', (req, res) => {
res.send('404', {
title: 404,
name: 'James Olaleye',
errorMessage: 'Page not found',
});
});
However, My IDE is warning about this message:
express deprecated res.send(status, body): Use
res.status(status).send(body) instead
And with the above code, My Browser is returning the following payload as a JSON object:
{
"title": 404,
"name": "James Olaleye",
"errorMessage": "Page not found"
}
What I want, is to display a 404 Not found page to the user, how can this be achived?
You have two seperate problem
1: you are using an old way to response to the request insted use this res.status(STATUS_CODE).send(BODY)
2: you are sending a json yet you want to display a 404 page in this case you need to send a html template
so your code should look like this
app.get('*', (req, res) => {
res.status(404).send("<div>404 Not Found</div>");
});
I updated your question a bit to make it clearer for future references.
the method res.send is deprecated, among other things because it's usages is too ambiguous. A server response, can be a lot of things, it can be a page, it can be a file, and it can be a simple JSON object (which you have here).
In your case, when you run res.send(404,{ /*...*/ }), the express app assumes you want to send a JSON object, so it does just that.
There are multiple possible ways, to achieve what you want, but I will stick to the most simple solution.
If you want to display an HTML page, in the most simplest form, you can actually just change your piece of code to do this instead:
app.status(404).send(`<h1>Page not found</h1>`)
This will essentially, show a page, instead of a JSON object.
You can even define the whole HTML file if you like:
app.status(404).send(
`
<html>
<!DOCTYPE html>
<head>
<title>404</title>
</head>
<body>
<h1>James Olaleye</h1>
<h1>Page Not Found</h1>
</body>
</html>
`
)
This would be the fastest way to achieve what you want.
A step further, would be to create an HTML file some where in your app, and to send the HTML file instead.
If your source code looks like this:
/
src/
index.js
htmls/
404.html
<!-- htmls/404.html -->
<html>
<!DOCTYPE html>
<head>
<title>404</title>
</head>
<body>
<h1>James Olaleye</h1>
<h1>Page Not Found</h1>
</body>
</html>
// src/index.js
const express = require('express');
const app = express();
const path = require('path');
const PORT = 3000;
app.get('/', function(req, res) {
const options = {
root: path.join(__dirname, '..', 'htmls')
};
res.sendFile('404.html', options, function (err) {
if (err) {
next(err);
} else {
console.log('Sent:', fileName);
}
});
});
This would allow you to have multiple HTML files which you can send around.
There are like I stated, other options as well, but that would make this answer way too long and out of scope. If you are interested, you can research Using template engines with Express and start with the following link.
Happy coding :)

How can I deploy the auth0 app to bluemix

I am using a sample project from auth0.com to customize the login page for my app and enable social media login. However I encounter some problem when I try to deploy it to bluemix.
The video tutorial I follow is https://www.youtube.com/watch?v=sHhNoV-sS_I&t=559s
however the sample project is a little bit different from the one in video. It required the command "npm serve" to run it. When I push my project using cf push it shows noappdecked. How can I deploy my project to bluemix?
the app.js code and html code is like
<!DOCTYPE html>
<html>
<head>
<title>Auth0-VanillaJS</title>
<meta charset="utf-8">
<!-- Auth0 lock script -->
<script src="//cdn.auth0.com/js/lock/10.3.0/lock.min.js"></script>
<script src="auth0-variables.js"></script>
<script src="app.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<img alt="avatar" id="avatar" style="display:none;">
<p>Welcome <span id="nickname"></span></p>
<button type="submit" id="btn-login">Sign In</button>
<button type="submit" id="btn-logout" style="display:none;">Sign Out</button>
</body>
window.addEventListener('load', function() {
var lock = new Auth0Lock(AUTH0_CLIENT_ID, AUTH0_DOMAIN);
// buttons
var btn_login = document.getElementById('btn-login');
var btn_logout = document.getElementById('btn-logout');
btn_login.addEventListener('click', function() {
lock.show();
});
btn_logout.addEventListener('click', function() {
logout();
});
lock.on("authenticated", function(authResult) {
lock.getProfile(authResult.idToken, function(error, profile) {
if (error) {
// Handle error
return;
}
localStorage.setItem('id_token', authResult.idToken);
// Display user information
show_profile_info(profile);
});
});
//retrieve the profile:
var retrieve_profile = function() {
var id_token = localStorage.getItem('id_token');
if (id_token) {
lock.getProfile(id_token, function (err, profile) {
if (err) {
return alert('There was an error getting the profile: ' + err.message);
}
// Display user information
show_profile_info(profile);
});
}
};
var show_profile_info = function(profile) {
var avatar = document.getElementById('avatar');
document.getElementById('nickname').textContent = profile.nickname;
btn_login.style.display = "none";
avatar.src = profile.picture;
avatar.style.display = "block";
btn_logout.style.display = "block";
};
var logout = function() {
localStorage.removeItem('id_token');
window.location.href = "/";
};
retrieve_profile();
});
You would use the package.json method documented at https://console.ng.bluemix.net/docs/runtimes/nodejs/index.html#nodejs_runtime , first to declare the serve package as one of your dependencies, then to indicate what the scripts.start script should do (which is run npm serve). You can use npm init (https://docs.npmjs.com/cli/init) to create a starting package.json file if you don't already have one.

reCaptcha + RequireJS

How can I import recaptcha using requirejs. I already tryed several things and nothing works.
I need do that to be able to render it by my own using the method render of reCaptcha once it has been loaded.
require.config({
paths: {
'recaptcha': 'http://www.google.com/recaptcha/api'
}
});
require( ['recaptcha'], function( recaptcha ) {
// do something with recaptcha
// recaptcha.render /// at this point recaptcha is undefined
console.log(recaptcha);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.2.0/require.min.js"></script>
Yes I have a solution for you. So what ends up happening is that recaptcha can't render until it has loaded what it needs from the google api.
So what you need to do is the following (also don't use http/https in your paths):
require.config({
paths: {
'recaptcha': '//www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit'
}
});
Now that will allow a callback to be executed after the necessary libraries have been downloaded from the google API.
This callback needs to be global unfortunately.
JS
var requireConfig = {
paths: {
'recaptcha': '//www.google.com/recaptcha/api.js? onload=onloadCallback&render=explicit'
}
};
function render(id) {
console.log('[info] - render');
recaptchaClientId = grecaptcha.render(id, {
'sitekey': '6LdntQgUAAAAANdffhZl0tIHw0fqT3MwNOlAI-xY',
'theme': 'light'
});
};
window.renderRecaptcha = render;
var onloadCallback = function() {
console.log('[info] - onLoadCallback');
if (!document.getElementById('g-recaptcha')) {
return;
}
window.renderRecaptcha('g-recaptcha');
};
requirejs.config(requireConfig);
require(['recaptcha'], function(recaptcha) {
});
HTML
<body>
<form action="?" method="POST">
<div id="g-recaptcha"></div>
<br/>
<input type="submit" value="Submit">
</form>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.14/require.js"> </script>
</body>
I hope that works for you!
Link to Example: https://jsbin.com/kowepo/edit?html,js,console,output
I know this question is a bit old, but I discovered another solution recently in my project that does not require the creation of global methods. This solution ended up being a very simple addition to the OP's first attempt at using Google reCaptcha with RequireJS.
In main.js, add the following: (exactly like the OP has it)
require.config({
paths: {
'recaptcha': 'http://www.google.com/recaptcha/api'
}
});
In your JS file where you're doing the explicit render, do the following:
require( ['recaptcha'], function(recaptcha) {
// render when recaptcha is ready
// injecting recaptcha here will give access to the grecaptcha object and it's ready method
grecaptcha.ready(function()
grecaptcha.render('elementId', {
'sitekey': 'SITE_KEY',
'callback': someCallbackMethod
});
);
});
This worked for me and I believe it's a cleaner solution!

React Components on the Server

I've been playing around with React for a while now but still can't wrap my head around on how to integrate it with an existing node/express/handlebars app.
For example, if I had a feed component which required json data to be fetched from AWS - how do I handle this.
var VideoFeed = require('./component/VideoFeed');
app.use('/', function(res, req) {
DataService.getVideoFeed().then(function(data) {
res.render('home', {videoComponent: React.renderToString(<VideoFeed feed={data} />);
});
});
Home
<!DOCTYPE html>
<body>
Some sample text. Here's the Video Feed
{{videoComponent}}
</body>
</html>

Consuming a Stream create using Node.JS

I have an application, which streams an MP3 using Node.JS. Currently this is done through the following post route...
app.post('/item/listen',routes.streamFile)
...
exports.streamFile = function(req, res){
console.log("The name is "+ req.param('name'))
playlistProvider.streamFile(res, req.param('name'))
}
...
PlaylistProvider.prototype.streamFile = function(res, filename){
res.contentType("audio/mpeg3");
var readstream = gfs.createReadStream(filename, {
"content_type": "audio/mpeg3",
"metadata":{
"author": "Jackie"
},
"chunk_size": 1024*4 });
console.log("!")
readstream.pipe(res);
}
Is there anyone that can help me read this on the client side? I would like to use either JPlayer or HTML5, but am open to other options.
So the real problem here was, we are "requesting a file" so this would be better as a GET request. In order to accomplish this, I used the express "RESTful" syntax '/item/listen/:name'. This then allows you to use the JPlayer the way specified in the links provided by the previous poster.
I'm assuming you didn't bother visiting their site because had you done so, you would have seen several examples of how to achieve this using HTML5/JPlayer. The following is a bare-bones example provided by their online developer's documentation:
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
<script type="text/javascript" src="/js/jquery.jplayer.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("#jquery_jplayer_1").jPlayer({
ready: function() {
$(this).jPlayer("setMedia", {
mp3: "http://www.jplayer.org/audio/mp3/Miaow-snip-Stirring-of-a-fool.mp3"
}).jPlayer("play");
var click = document.ontouchstart === undefined ? 'click' : 'touchstart';
var kickoff = function () {
$("#jquery_jplayer_1").jPlayer("play");
document.documentElement.removeEventListener(click, kickoff, true);
};
document.documentElement.addEventListener(click, kickoff, true);
},
loop: true,
swfPath: "/js"
});
});
</script>
</head>
<body>
<div id="jquery_jplayer_1"></div>
</body>
</html>

Resources